home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / tde40.zip / block.c < prev    next >
C/C++ Source or Header  |  1994-06-05  |  90KB  |  2,879 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - block commands module
  10.  * Purpose: This file contains all the commands than manipulate blocks.
  11.  * File:    block.c
  12.  * Author:  Douglas Thomson
  13.  * System:  this file is intended to be system-independent
  14.  * Date:    October 1, 1989
  15.  */
  16. /*********************  end of original comments   ********************/
  17.  
  18. /*
  19.  * In the DTE editor, Doug only supported functions for STREAM blocks.
  20.  *
  21.  * The block routines have been EXTENSIVELY rewritten.  This editor uses LINE,
  22.  * STREAM, and BOX blocks.  That is, one may mark entire lines, streams of
  23.  * characters, or column blocks.  Block operations are done in place.  There
  24.  * are no paste and cut buffers.  In limited memory situations, larger block
  25.  * operations can be carried out.  Block operations can be done within or
  26.  * across files.
  27.  *
  28.  * In TDE, version 1.1, I separated the BOX and LINE actions.
  29.  *
  30.  * In TDE, version 1.3, I put STREAM blocks back in.  Added block upper case,
  31.  *  block lower case, and block strip high bit.
  32.  *
  33.  * In TDE, version 1.4, I added a block number function.  Here at our lab,
  34.  *  I often need to number samples, lines, etc..., comes in fairly useful.
  35.  *
  36.  * In TDE, version 2.0, I added a box block sort function.
  37.  *
  38.  * In TDE, version 2.0e, I added BlockRot13, BlockFixUUE, and BlockEmailReply.
  39.  *
  40.  * In TDE, version 2.2, the big text buffer was changed to a double linked list.
  41.  *  all characters in the line of each node must be accurately counted.
  42.  *
  43.  * New editor name:  TDE, the Thomson-Davis Editor.
  44.  * Author:           Frank Davis
  45.  * Date:             June 5, 1991, version 1.0
  46.  * Date:             July 29, 1991, version 1.1
  47.  * Date:             October 5, 1991, version 1.2
  48.  * Date:             January 20, 1992, version 1.3
  49.  * Date:             February 17, 1992, version 1.4
  50.  * Date:             April 1, 1992, version 1.5
  51.  * Date:             June 5, 1992, version 2.0
  52.  * Date:             October 31, 1992, version 2.1
  53.  * Date:             April 1, 1993, version 2.2
  54.  * Date:             June 5, 1993, version 3.0
  55.  * Date:             August 29, 1993, version 3.1
  56.  * Date:             November 13, 1993, version 3.2
  57.  * Date:             June 5, 1994, version 4.0
  58.  *
  59.  * This modification of Douglas Thomson's code is released into the
  60.  *  public domain, Frank Davis.  You may distribute it freely.
  61.  */
  62.  
  63. #include "tdestr.h"
  64. #include "common.h"
  65. #include "tdefunc.h"
  66. #include "define.h"
  67.  
  68.  
  69. /*
  70.  * Name:    mark_block
  71.  * Class:   primary editor function
  72.  * Purpose: To record the position of the start of the block in the file.
  73.  * Date:    June 5, 1991
  74.  * Passed:  window:  pointer to current window
  75.  * Notes:   Assume the user will mark begin and end of a block in either
  76.  *           line, stream, or box mode.  If the user mixes types, then block
  77.  *           type defaults to current block type.
  78.  */
  79. int  mark_block( TDE_WIN *window )
  80. {
  81. int type;
  82. int num;
  83. long lnum;
  84. register file_infos *file;      /* temporary file variable */
  85. register TDE_WIN *win;          /* put window pointer in a register */
  86. int rc;
  87.  
  88.    win  = window;
  89.    file = win->file_info;
  90.    if (win->rline > file->length || win->ll->len == EOF)
  91.       return( ERROR );
  92.    if (g_status.marked == FALSE) {
  93.       g_status.marked = TRUE;
  94.       g_status.marked_file = file;
  95.    }
  96.    if (g_status.command == MarkBox)
  97.       type = BOX;
  98.    else if (g_status.command == MarkLine)
  99.       type = LINE;
  100.    else if (g_status.command == MarkStream)
  101.       type = STREAM;
  102.    else
  103.       return( ERROR );
  104.  
  105.    rc = OK;
  106.    /*
  107.     * define blocks for only one file.  it is ok to modify blocks in any window
  108.     * pointing to original marked file.
  109.     */
  110.    if (file == g_status.marked_file) {
  111.  
  112.       /*
  113.        * mark beginning and ending column regardless of block mode.
  114.        */
  115.       if (file->block_type == NOTMARKED) {
  116.          file->block_ec  = file->block_bc = win->rcol;
  117.          file->block_er  = file->block_br = win->rline;
  118.       } else {
  119.          if (file->block_br > win->rline) {
  120.             file->block_br = win->rline;
  121.             if (file->block_bc < win->rcol && type != STREAM)
  122.                file->block_ec = win->rcol;
  123.             else
  124.                file->block_bc = win->rcol;
  125.          } else {
  126.             if (type != STREAM) {
  127.                file->block_ec = win->rcol;
  128.                file->block_er = win->rline;
  129.             } else {
  130.                if (win->rline == file->block_br &&
  131.                    win->rline == file->block_er) {
  132.                   if (win->rcol < file->block_bc)
  133.                      file->block_bc = win->rcol;
  134.                   else
  135.                      file->block_ec = win->rcol;
  136.                } else if (win->rline == file->block_br)
  137.                   file->block_bc = win->rcol;
  138.                else {
  139.                   file->block_ec = win->rcol;
  140.                   file->block_er = win->rline;
  141.                }
  142.             }
  143.          }
  144.  
  145.          /*
  146.           * if user marks ending line less than beginning line then switch
  147.           */
  148.          if (file->block_er < file->block_br) {
  149.             lnum = file->block_er;
  150.             file->block_er = file->block_br;
  151.             file->block_br = lnum;
  152.          }
  153.  
  154.          /*
  155.           * if user marks ending column less than beginning column then switch
  156.           */
  157.          if ((file->block_ec < file->block_bc) && (type != STREAM ||
  158.               (type == STREAM && file->block_br == file->block_er))) {
  159.             num = file->block_ec;
  160.             file->block_ec = file->block_bc;
  161.             file->block_bc = num;
  162.          }
  163.       }
  164.  
  165.       /*
  166.        * block type in now defined.  if user mixes block types then block
  167.        * is defined as current block type.
  168.        */
  169.       if (file->block_type != NOTMARKED) {
  170.          /*
  171.           * if block type goes to BOX, check to make sure ec is greater than
  172.           * or equal to bc.  ec can be less than bc in STREAM blocks.
  173.           */
  174.          if (type == BOX) {
  175.             if (file->block_ec < file->block_bc) {
  176.                num = file->block_ec;
  177.                file->block_ec = file->block_bc;
  178.                file->block_bc = num;
  179.             }
  180.          }
  181.       }
  182.  
  183.       assert( file->block_er >= file->block_br );
  184.  
  185.       file->block_type = type;
  186.       file->dirty = GLOBAL;
  187.    } else {
  188.       /*
  189.        * block already defined
  190.        */
  191.       error( WARNING, win->bottom_line, block1 );
  192.       rc = ERROR;
  193.    }
  194.    return( rc );
  195. }
  196.  
  197.  
  198. /*
  199.  * Name:    unmark_block
  200.  * Class:   primary editor function
  201.  * Purpose: To set all block information to NULL or 0
  202.  * Date:    June 5, 1991
  203.  * Passed:  arg_filler: variable to match array of function pointers prototype
  204.  * Notes:   Reset all block variables if marked, otherwise return.
  205.  *           If a marked block is unmarked then redraw the screen(s).
  206.  */
  207. int  unmark_block( TDE_WIN *arg_filler )
  208. {
  209. register file_infos *marked_file;
  210.  
  211.    if (g_status.marked == TRUE) {
  212.       marked_file              = g_status.marked_file;
  213.       g_status.marked          = FALSE;
  214.       g_status.marked_file     = NULL;
  215.       marked_file->block_start = NULL;
  216.       marked_file->block_end   = NULL;
  217.       marked_file->block_bc    = marked_file->block_ec = 0;
  218.       marked_file->block_br    = marked_file->block_er = 0l;
  219.       if (marked_file->block_type)
  220.          marked_file->dirty = GLOBAL;
  221.       marked_file->block_type  = NOTMARKED;
  222.    }
  223.    return( OK );
  224. }
  225.  
  226.  
  227. /*
  228.  * Name:    restore_marked_block
  229.  * Class:   helper function
  230.  * Purpose: To restore block beginning and ending row after an editing function
  231.  * Date:    June 5, 1991
  232.  * Passed:  window:  pointer to current window
  233.  *          net_change: number of bytes added or subtracted
  234.  * Notes:   If a change has been made before the marked block then the
  235.  *           beginning and ending row need to be adjusted by the number of
  236.  *           lines added or subtracted from file.
  237.  */
  238. void restore_marked_block( TDE_WIN *window, int net_change )
  239. {
  240. long length;
  241. register file_infos *marked_file;
  242.  
  243.    if (g_status.marked == TRUE && net_change != 0) {
  244.       marked_file = g_status.marked_file;
  245.       length = marked_file->length;
  246.  
  247.       /*
  248.        * restore is needed only if a block is defined and window->file_info is
  249.        * same as marked file and there was a net change in file length.
  250.        */
  251.       if (marked_file == window->file_info) {
  252.  
  253.          /*
  254.           * if cursor is before marked block then adjust block by net change.
  255.           */
  256.          if (marked_file->block_br > window->rline) {
  257.             marked_file->block_br += net_change;
  258.             marked_file->block_er += net_change;
  259.             marked_file->dirty = GLOBAL;
  260.          /*
  261.           * if cursor is somewhere in marked block don't restore, do redisplay
  262.           */
  263.          } else if (marked_file->block_er >= window->rline)
  264.             marked_file->dirty = GLOBAL;
  265.  
  266.          /*
  267.           * check for lines of marked block beyond end of file
  268.           */
  269.          if (marked_file->block_br > length)
  270.             unmark_block( window );
  271.          else if (marked_file->block_er > length) {
  272.             marked_file->block_er = length;
  273.             marked_file->dirty = GLOBAL;
  274.          }
  275.       }
  276.    }
  277. }
  278.  
  279.  
  280. /*
  281.  * Name:    prepare_block
  282.  * Class:   helper function
  283.  * Purpose: To prepare a window/file for a block read, move or copy.
  284.  * Date:    June 5, 1991
  285.  * Passed:  window:  pointer to current window
  286.  *          file: pointer to file information.
  287.  *          text_line: pointer to line in file to prepare.
  288.  *          lend: line length.
  289.  *          bc: beginning column of BOX.
  290.  * Notes:   The main complication is that the cursor may be beyond the end
  291.  *           of the current line, in which case extra padding spaces have
  292.  *           to be added before the block operation can take place.
  293.  *           this only occurs in BOX and STREAM operations.
  294.  *          since we are padding a line, do not trim trailing space.
  295.  */
  296. int  prepare_block( TDE_WIN *window, line_list_ptr ll, int bc )
  297. {
  298. register int pad = 0;   /* amount of padding to be added */
  299. register int len;
  300.  
  301.    assert( bc >= 0 );
  302.    assert( bc < MAX_LINE_LENGTH );
  303.    assert( ll->len != EOF );
  304.    assert( g_status.copied == FALSE );
  305.  
  306.    copy_line( ll );
  307.    detab_linebuff( );
  308.  
  309.    len = g_status.line_buff_len;
  310.    pad = bc - len;
  311.    if (pad > 0) {
  312.       /*
  313.        * insert the padding spaces
  314.        */
  315.  
  316.       assert( pad >= 0 );
  317.       assert( pad < MAX_LINE_LENGTH );
  318.  
  319.       memset( g_status.line_buff+len, ' ', pad );
  320.       g_status.line_buff_len += pad;
  321.    }
  322.    /*
  323.     * if mode.inflate_tabs, let's don't entab the line until we get
  324.     *   thru processing this line, e.g. copying, numbering....
  325.     */
  326.    return( un_copy_line( ll, window, FALSE ) );
  327. }
  328.  
  329.  
  330. /*
  331.  * Name:    pad_dest_line
  332.  * Class:   helper function
  333.  * Purpose: To prepare a window/file for a block move or copy.
  334.  * Date:    June 5, 1991
  335.  * Passed:  window:  pointer to current window
  336.  *          dest_file: pointer to file information.
  337.  *          dest_line: pointer to line in file to prepare.
  338.  *          ll:        pointer to linked list node to insert new node
  339.  * Notes:   We are doing a BOX action (except DELETE).   We have come
  340.  *          to the end of the file and have no more lines.  All this
  341.  *          routine does is add a blank line to file.
  342.  */
  343. int  pad_dest_line( TDE_WIN *window, file_infos *dest_file, line_list_ptr ll )
  344. {
  345. int rc;
  346. text_ptr l;
  347. line_list_ptr new_node;
  348.  
  349.    rc = OK;
  350.    l = NULL;
  351.    new_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  352.    if (rc == OK) {
  353.       new_node->len   = 0;
  354.       new_node->dirty = FALSE;
  355.       new_node->line  = l;
  356.       if (ll->next != NULL) {
  357.          ll->next->prev = new_node;
  358.          new_node->next = ll->next;
  359.          ll->next = new_node;
  360.          new_node->prev = ll;
  361.       } else {
  362.          new_node->next = ll;
  363.          if (ll->prev != NULL)
  364.             ll->prev->next = new_node;
  365.          new_node->prev = ll->prev;
  366.          ll->prev = new_node;
  367.          if (new_node->prev == NULL)
  368.             window->file_info->line_list = new_node;
  369.       }
  370.       ++dest_file->length;
  371.    } else {
  372.       /*
  373.        * file too big
  374.        */
  375.       error( WARNING, window->bottom_line, block4 );
  376.       if (new_node != NULL)
  377.          my_free( new_node );
  378.       rc = ERROR;
  379.    }
  380.    return( rc );
  381. }
  382.  
  383.  
  384. /*
  385.  * Name:    move_copy_delete_overlay_block
  386.  * Class:   primary editor function
  387.  * Purpose: Master BOX, STREAM, or LINE routine.
  388.  * Date:    June 5, 1991
  389.  * Passed:  window:  pointer to current window
  390.  * Notes:   Operations on BOXs, STREAMs, or LINEs require several common
  391.  *           operations.  All require finding the beginning and ending marks.
  392.  *          This routine will handle block operations across files.  Since one
  393.  *           must determine the relationship of source and destination blocks
  394.  *           within a file, it is relatively easy to expand this relationship
  395.  *           across files.
  396.  *          This is probably the most complicated routine in the editor.  It
  397.  *           is not easy to understand.
  398.  */
  399. int  move_copy_delete_overlay_block( TDE_WIN *window )
  400. {
  401. int  action;
  402. TDE_WIN *source_window;          /* source window for block moves */
  403. line_list_ptr source;           /* source for block moves */
  404. line_list_ptr dest;             /* destination for block moves */
  405. long number;                    /* number of characters for block moves */
  406. int  lens;                      /* length of source line */
  407. int  lend;                      /* length of destination line */
  408. int  add;                       /* characters being added from another line */
  409. int  block_len;                 /* length of the block */
  410. line_list_ptr block_start;      /* start of block in file */
  411. line_list_ptr block_end;  /* end of block in file - not same for LINE or BOX */
  412. int  prompt_line;
  413. int  same;                      /* are dest and source files the same file? */
  414. int  source_first;              /* is source file lower in memory than dest */
  415. file_infos *source_file;
  416. file_infos *dest_file;
  417. int  rcol, bc, ec;              /* temporary column variables */
  418. long rline;                     /* temporary real line variable */
  419. long br, er;                    /* temporary line variables */
  420. long block_num;                 /* starting number for block number */
  421. long block_inc;                 /* increment to use for block number */
  422. int  block_just;                /* left or right justify numbers? */
  423. int  block_type;
  424. int  fill_char;
  425. int  rc;
  426.  
  427.    /*
  428.     * initialize block variables
  429.     */
  430.    entab_linebuff( );
  431.    rc = un_copy_line( window->ll, window, TRUE );
  432.    if (g_status.marked == FALSE || rc == ERROR)
  433.       return( ERROR );
  434.    switch (g_status.command) {
  435.       case MoveBlock :
  436.          action = MOVE;
  437.          break;
  438.       case DeleteBlock :
  439.          action = DELETE;
  440.          break;
  441.       case CopyBlock :
  442.          action = COPY;
  443.          break;
  444.       case KopyBlock :
  445.          action = KOPY;
  446.          break;
  447.       case FillBlock :
  448.          action = FILL;
  449.          break;
  450.       case OverlayBlock :
  451.          action = OVERLAY;
  452.          break;
  453.       case NumberBlock :
  454.          action = NUMBER;
  455.          break;
  456.       case SwapBlock :
  457.          action = SWAP;
  458.          break;
  459.       default :
  460.          return( ERROR );
  461.    }
  462.    source_file = g_status.marked_file;
  463.    source_window = g_status.window_list;
  464.    for (; ptoul( source_window->file_info ) != ptoul( source_file );)
  465.       source_window = source_window->next;
  466.    prompt_line = window->bottom_line;
  467.    dest_file = window->file_info;
  468.    check_block( );
  469.    if (g_status.marked == FALSE)
  470.       return( ERROR );
  471.    block_start = source_file->block_start;
  472.    block_end = source_file->block_end;
  473.    if (block_start == NULL  ||  block_end == NULL)
  474.       return( ERROR );
  475.  
  476.    block_type = source_file->block_type;
  477.    if (block_type != LINE  &&  block_type != STREAM  &&  block_type != BOX)
  478.       return( ERROR );
  479.  
  480.    dest = window->ll;
  481.    rline = window->rline;
  482.    if (dest->len == EOF)
  483.       return( ERROR );
  484.    rc = OK;
  485.  
  486.    /*
  487.     * set up Beginning Column, Ending Column, Beginning Row, Ending Row
  488.     */
  489.    bc = source_file->block_bc;
  490.    ec = source_file->block_ec;
  491.    br = source_file->block_br;
  492.    er = source_file->block_er;
  493.  
  494.    /*
  495.     * if we are BOX FILLing or BOX NUMBERing, beginning column is bc,
  496.     *   not the column of cursor
  497.     */
  498.    rcol =  (action == FILL || action == NUMBER) ? bc : window->rcol;
  499.  
  500.    /*
  501.     * must find out if source and destination file are the same.
  502.     * it don't matter with FILL and DELETE - those actions only modify the
  503.     * source file.
  504.     */
  505.    source_first = same = FALSE;
  506.    if (action == FILL) {
  507.       if (block_type == BOX) {
  508.          if (get_block_fill_char( window, &fill_char ) == ERROR)
  509.             return( ERROR );
  510.          dest = block_start;
  511.          same = TRUE;
  512.       } else {
  513.          /*
  514.           * can only fill box blocks.
  515.           */
  516.          error( WARNING, prompt_line, block2 );
  517.          return( ERROR );
  518.       }
  519.    }
  520.    block_inc = 1;
  521.    if (action == NUMBER) {
  522.       if (block_type == BOX) {
  523.          if (get_block_numbers( window, &block_num, &block_inc, &block_just )
  524.               == ERROR)
  525.             return( ERROR );
  526.          dest = block_start;
  527.          same = TRUE;
  528.       } else {
  529.          /*
  530.           * can only number box blocks.
  531.           */
  532.          error( WARNING, prompt_line, block3a );
  533.          return( ERROR );
  534.       }
  535.    }
  536.    if (action == SWAP) {
  537.       if (block_type != BOX) {
  538.          /*
  539.           * can only swap box blocks.
  540.           */
  541.          error( WARNING, prompt_line, block3b );
  542.          return( ERROR );
  543.       }
  544.    }
  545.    if (source_file == dest_file && action != DELETE && action != FILL) {
  546.       same = TRUE;
  547.       if (block_type == BOX && action == MOVE) {
  548.          if (rline == br  &&  (rcol >= bc && rcol <= ec))
  549.             /*
  550.              * a block moved to within the block itself has no effect
  551.              */
  552.             return( ERROR );
  553.       } else if (block_type == LINE || block_type == STREAM) {
  554.          if (rline >= br && rline <= er) {
  555.             if (block_type == LINE) {
  556.                 /*
  557.                  * if COPYing or KOPYing within the block itself, reposition the
  558.                  * destination to the next line after the block (if it exists)
  559.                  */
  560.                if (action == COPY || action == KOPY)
  561.                   dest = block_end;
  562.                 /*
  563.                  * a block moved to within the block itself has no effect
  564.                  */
  565.                else if (action == MOVE)
  566.                   return( ERROR );
  567.             } else {
  568.  
  569.                /*
  570.                 * to find out if cursor is in a STREAM block we have to do
  571.                 * a few more tests.  if cursor is on the beginning row or
  572.                 * ending row, then check the beginning and ending column.
  573.                 */
  574.                if ((rline > br && rline < er) ||
  575.                    (br == er && rcol >= bc && rcol <= ec) ||
  576.                    (br != er && ((rline == br && rcol >= bc) ||
  577.                                  (rline == er && rcol <= ec)))) {
  578.  
  579.                   /*
  580.                    * if the cursor is in middle of STREAM, make destination
  581.                    * the last character following the STREAM block.
  582.                    */
  583.                   if (action == COPY || action == KOPY) {
  584.                      dest = block_end;
  585.                      rcol = ec + 1;
  586.                      rline = er;
  587.                   } else if (action == MOVE)
  588.                      return( ERROR );
  589.                }
  590.             }
  591.          }
  592.       }
  593.    }
  594.    if (br < rline)
  595.       source_first = TRUE;
  596.  
  597.    /*
  598.     * 1. can't create lines greater than MAX_LINE_LENGTH
  599.     * 2. if we are FILLing a BOX - fill block buff once right here
  600.     * 3. only allow overlaying BOXs
  601.     */
  602.    block_len = (ec+1) - bc;
  603.    if (block_type == BOX) {
  604.       if (action != DELETE && action != FILL) {
  605.          if (rcol + block_len > MAX_LINE_LENGTH) {
  606.             /*
  607.              * line too long
  608.              */
  609.             error( WARNING, prompt_line, ltol );
  610.             return( ERROR );
  611.          }
  612.       }
  613.    } else if (block_type == LINE) {
  614.       block_len = 0;
  615.       if (action == OVERLAY) {
  616.          /*
  617.           * can only overlay box blocks
  618.           */
  619.          error( WARNING, prompt_line, block5 );
  620.          return( ERROR );
  621.       }
  622.    } else if (block_type == STREAM) {
  623.  
  624.       if (action == OVERLAY) {
  625.          /*
  626.           * can only overlay box blocks
  627.           */
  628.          error( WARNING, prompt_line, block5 );
  629.          return( ERROR );
  630.       }
  631.  
  632.       lend = block_end->len;
  633.       if (action == DELETE || action == MOVE) {
  634.  
  635.          /*
  636.           * Is what's left on start of STREAM block line plus what's left at
  637.           * end of STREAM block line too long?
  638.           */
  639.          if (lend > ec)
  640.             lend -= ec;
  641.          else
  642.             lend = 0;
  643.          if (bc + lend > MAX_LINE_LENGTH) {
  644.             /*
  645.              * line too long
  646.              */
  647.             error( WARNING, prompt_line, ltol );
  648.             return( ERROR );
  649.          }
  650.       }
  651.  
  652.       if (action != DELETE) {
  653.  
  654.          /*
  655.           * We are doing a MOVE, COPY, or KOPY.  Find out if what's on the
  656.           * current line plus the start of the STREAM line are too long.
  657.           * Then find out if end of the STREAM line plus what's left of
  658.           * the current line are too long.
  659.           */
  660.          lens = block_start->len;
  661.  
  662.          /*
  663.           * if we had to move the destination of the STREAM COPY or KOPY
  664.           * to the end of the STREAM block, then dest and window->ll->line
  665.           * will not be the same.  In this case, set length to length of
  666.           * first line in STREAM block.  Then we can add the residue of
  667.           * the first line in block plus residue of the last line of block.
  668.           */
  669.          if (dest->line == window->ll->line)
  670.             add = dest->len;
  671.          else
  672.             add = lens;
  673.  
  674.          /*
  675.           * Is current line plus start of STREAM block line too long?
  676.           */
  677.          if (lens > bc)
  678.             lens -= bc;
  679.          else
  680.             lens = 0;
  681.          if (rcol + lens > MAX_LINE_LENGTH) {
  682.             /*
  683.              * line too long
  684.              */
  685.             error( WARNING, prompt_line, ltol );
  686.             return( ERROR );
  687.          }
  688.  
  689.          /*
  690.           * Is residue of current line plus residue of STREAM block line
  691.           * too long?
  692.           */
  693.          if (add > bc)
  694.             add -= bc;
  695.          else
  696.             add = 0;
  697.          if (lend > ec)
  698.             lend -= ec;
  699.          else
  700.             lend = 0;
  701.          if (add + lend > MAX_LINE_LENGTH) {
  702.             /*
  703.              * line too long
  704.              */
  705.             error( WARNING, prompt_line, ltol );
  706.             return( ERROR );
  707.          }
  708.       }
  709.       if (ptoul( block_start ) == ptoul( block_end )) {
  710.          block_type = BOX;
  711.          block_len = (ec+1) - bc;
  712.       }
  713.    }
  714.  
  715.    if (mode.do_backups == TRUE) {
  716.       switch (action) {
  717.          case MOVE :
  718.          case DELETE :
  719.          case COPY :
  720.          case KOPY :
  721.          case SWAP :
  722.             window->file_info->modified = TRUE;
  723.             rc = backup_file( window );
  724.             break;
  725.       }
  726.       switch (action) {
  727.          case MOVE :
  728.          case DELETE :
  729.          case FILL :
  730.          case NUMBER :
  731.          case SWAP :
  732.             source_window->file_info->modified = TRUE;
  733.             if (rc != ERROR)
  734.                rc = backup_file( source_window );
  735.             break;
  736.       }
  737.    }
  738.    source = block_start;
  739.  
  740.    assert( block_start != NULL );
  741.    assert( block_start->len != EOF );
  742.    assert( block_end != NULL );
  743.    assert( block_end->len != EOF );
  744.  
  745.    if (block_type == LINE)
  746.       do_line_block( window,  source_window,  action,
  747.                      source_file,  dest_file,  block_start,  block_end,
  748.                      source,  dest,  br,  er,  &rc );
  749.  
  750.    else if (block_type == STREAM)
  751.       do_stream_block( window,  source_window,  action,
  752.                        source_file,  dest_file,  block_start,  block_end,
  753.                        source,  dest,  rline,  br,  er,  bc,  ec,  rcol,  &rc );
  754.  
  755.    else
  756.       do_box_block( window,  source_window,  action,
  757.                     source_file,  dest_file,  source,  dest,  br,  er,
  758.                     block_inc, rline, block_num, block_just, fill_char,
  759.                     same, block_len, bc, ec,  rcol, &rc );
  760.  
  761.    dest_file->modified = TRUE;
  762.    dest_file->dirty = GLOBAL;
  763.    if (action == MOVE || action == DELETE || action == FILL || action==NUMBER) {
  764.       source_file->modified = TRUE;
  765.       source_file->dirty = GLOBAL;
  766.    }
  767.  
  768.    /*
  769.     * unless we are doing a KOPY, FILL, NUMBER, or OVERLAY we need to unmark
  770.     * the block.  if we just did a KOPY, the beginning and ending may have
  771.     * changed.  so, we must readjust beginning and ending rows.
  772.     */
  773.    if (action == KOPY) {
  774.       if (same && !source_first && block_type == LINE  &&  rc != ERROR) {
  775.          number = (er+1) - br;
  776.          source_file->block_br += number;
  777.          source_file->block_er += number;
  778.       }
  779.    } else if (action != FILL && action != OVERLAY && action != NUMBER)
  780.       unmark_block( window );
  781.    show_avail_mem( );
  782.    g_status.copied = FALSE;
  783.    return( rc );
  784. }
  785.  
  786.  
  787. /*
  788.  * Name:    do_line_block
  789.  * Purpose: delete, move, copy, or kopy a LINE block
  790.  * Date:    April 1, 1993
  791.  * Passed:  window:  pointer to current window
  792.  * Passed:  window:         pointer to destination window (current window)
  793.  *          source_window:  pointer to source window
  794.  *          action:         block action  --  KOPY, MOVE, etc...
  795.  *          source_file:    pointer to source file structure
  796.  *          dest_file:      pointer to destination file
  797.  *          block_start:    pointer to first node in block
  798.  *          block_end:      pointer to last node in block
  799.  *          source:         pointer to source node
  800.  *          dest:           pointer to destination node
  801.  *          br:             beginning line number in marked block
  802.  *          er:             ending line number in marked block
  803.  *          rc:             return code
  804.  */
  805. void do_line_block( TDE_WIN *window,  TDE_WIN *source_window,  int action,
  806.                     file_infos *source_file,  file_infos *dest_file,
  807.                     line_list_ptr block_start,  line_list_ptr block_end,
  808.                     line_list_ptr source,  line_list_ptr dest,
  809.                     long br,  long er, int *rc )
  810. {
  811. line_list_ptr temp_ll;          /* temporary list pointer */
  812. text_ptr l;
  813. int  lens;                      /* length of source line */
  814. long li;                        /* temporary line variables */
  815. long diff;
  816.  
  817.    if (action == COPY || action == KOPY) {
  818.  
  819.       assert( br >= 1 );
  820.       assert( br <= source_file->length );
  821.       assert( er >= br );
  822.       assert( er <= source_file->length );
  823.  
  824.       for (li=br; li <= er  &&  *rc == OK; li++) {
  825.          lens = source->len;
  826.  
  827.          assert( lens * sizeof(char) < MAX_LINE_LENGTH );
  828.  
  829.          l = (text_ptr)my_malloc( lens * sizeof(char), rc );
  830.          temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), rc );
  831.          if (*rc == OK) {
  832.             if (lens > 0)
  833.                my_memcpy( l, source->line, lens );
  834.             temp_ll->line  = l;
  835.             temp_ll->len   = lens;
  836.             temp_ll->dirty = TRUE;
  837.  
  838.             if (dest->next != NULL) {
  839.                dest->next->prev = temp_ll;
  840.                temp_ll->next = dest->next;
  841.                dest->next = temp_ll;
  842.                temp_ll->prev = dest;
  843.             } else {
  844.                temp_ll->next = dest;
  845.                if (dest->prev != NULL)
  846.                   dest->prev->next = temp_ll;
  847.                temp_ll->prev = dest->prev;
  848.                dest->prev = temp_ll;
  849.                if (temp_ll->prev == NULL)
  850.                   window->file_info->line_list = temp_ll;
  851.             }
  852.  
  853.             dest = temp_ll;
  854.             source = source->next;
  855.          } else {
  856.             /*
  857.              * file too big
  858.              */
  859.             error( WARNING, window->bottom_line, dir3 );
  860.             if (l != NULL)
  861.                my_free( l );
  862.             if (temp_ll != NULL)
  863.                my_free( temp_ll );
  864.             *rc = ERROR;
  865.             er = li - 1;
  866.          }
  867.       }
  868.    } else if (action == MOVE) {
  869.       if (dest->len != EOF  &&  dest->next != NULL) {
  870.          temp_ll = block_start;
  871.          for (li=br; li <= er  &&  *rc == OK; li++) {
  872.             temp_ll->dirty = TRUE;
  873.             temp_ll = temp_ll->next;
  874.          }
  875.          if (block_start->prev == NULL)
  876.             source_file->line_list = block_end->next;
  877.          if (block_start->prev != NULL)
  878.             block_start->prev->next = block_end->next;
  879.          block_end->next->prev = block_start->prev;
  880.          dest->next->prev = block_end;
  881.          block_start->prev = dest;
  882.          block_end->next = dest->next;
  883.          dest->next = block_start;
  884.       }
  885.    } else if (action == DELETE) {
  886.       block_end->next->prev = block_start->prev;
  887.       if (block_start->prev == NULL)
  888.          source_file->line_list = block_end->next;
  889.       else
  890.          block_start->prev->next = block_end->next;
  891.       block_end->next = NULL;
  892.       while (block_start != NULL) {
  893.          temp_ll = block_start;
  894.          block_start = block_start->next;
  895.          if (temp_ll->line != NULL)
  896.             my_free( temp_ll->line );
  897.          my_free( temp_ll );
  898.       }
  899.    }
  900.  
  901.    diff =  er + 1L - br;
  902.    if (action == COPY || action == KOPY || action == MOVE)
  903.       dest_file->length += diff;
  904.    if (action == DELETE || action == MOVE)
  905.       source_file->length -= diff;
  906.    if (action == DELETE && source_window->rline >= br) {
  907.       source_window->rline -= diff;
  908.       if (source_window->rline < br)
  909.          source_window->rline = br;
  910.    }
  911.    /*
  912.     * restore all cursors in all windows
  913.     */
  914.    restore_cursors( dest_file );
  915.    if (dest_file != source_file)
  916.       restore_cursors( source_file );
  917.    show_avail_mem( );
  918. }
  919.  
  920.  
  921. /*
  922.  * Name:    do_stream_block
  923.  * Purpose: delete, move, copy, or kopy a STREAM block
  924.  * Date:    June 5, 1991
  925.  * Passed:  window:         pointer to destination window (current window)
  926.  *          source_window:  pointer to source window
  927.  *          action:         block action  --  KOPY, MOVE, etc...
  928.  *          source_file:    pointer to source file structure
  929.  *          dest_file:      pointer to destination file
  930.  *          block_start:    pointer to first node in block
  931.  *          block_end:      pointer to last node in block
  932.  *          source:         pointer to source node
  933.  *          dest:           pointer to destination node
  934.  *          rline:          current line number in destination file
  935.  *          br:             beginning line number in marked block
  936.  *          er:             ending line number in marked block
  937.  *          bc:             beginning column of block
  938.  *          ec:             ending column of block
  939.  *          rcol:           current column of cursor
  940.  *          rc:             return code
  941.  */
  942. void do_stream_block( TDE_WIN *window,  TDE_WIN *source_window,  int action,
  943.                     file_infos *source_file,  file_infos *dest_file,
  944.                     line_list_ptr block_start,  line_list_ptr block_end,
  945.                     line_list_ptr source,  line_list_ptr dest, long rline,
  946.                     long br,  long er, int bc, int ec, int rcol, int *rc )
  947. {
  948. line_list_ptr temp_ll;          /* temporary list pointer */
  949. text_ptr l;
  950. int  lens;                      /* length of source line */
  951. int  lend;                      /* length of destination line */
  952. long li;                        /* temporary line variables */
  953. long diff;
  954. TDE_WIN s_w, d_w;               /* a couple of temporary TDE_WINs */
  955.  
  956.    dup_window_info( &s_w, source_window );
  957.    dup_window_info( &d_w, window );
  958.    s_w.rline   = br;
  959.    s_w.ll      = block_start;
  960.    s_w.visible = FALSE;
  961.    d_w.rline   = rline;
  962.    d_w.ll      = dest;
  963.    d_w.visible = FALSE;
  964.  
  965.    /*
  966.     * pad the start of the STREAM block if needed.
  967.     */
  968.    lens = block_start->len;
  969.    detab_a_line( block_start->line, &lens );
  970.    if (lens < bc || mode.inflate_tabs)
  971.       *rc = prepare_block( &s_w, block_start, bc );
  972.  
  973.    /*
  974.     * pad the end of the STREAM block if needed.
  975.     */
  976.    lens = block_end->len;
  977.    detab_a_line( block_end->line, &lens );
  978.    if (*rc == OK  &&  (lens < ec+1  ||  mode.inflate_tabs))
  979.       *rc = prepare_block( &s_w, block_end, ec+1 );
  980.  
  981.    /*
  982.     * pad the destination line if necessary
  983.     */
  984.    copy_line( dest );
  985.    detab_linebuff( );
  986.    *rc = un_copy_line( dest, &d_w, FALSE );
  987.    lend = dest->len;
  988.    if (*rc == OK && (action==MOVE || action==COPY || action==KOPY)) {
  989.       if (lend < rcol || mode.inflate_tabs)
  990.          *rc = prepare_block( &d_w, dest, rcol );
  991.    }
  992.  
  993.    if ((action == COPY || action == KOPY) && *rc == OK) {
  994.  
  995.       /*
  996.        * concatenate the end of the STREAM block with the end of the
  997.        *   destination line.
  998.        */
  999.       lens = dest->len - rcol;
  1000.  
  1001.       assert( lens >= 0 );
  1002.       assert( lens <= MAX_LINE_LENGTH );
  1003.       assert( ec + 1 >= 0 );
  1004.       assert( ec + 1 <= MAX_LINE_LENGTH );
  1005.       assert( rcol >= 0 );
  1006.  
  1007.       my_memcpy( g_status.line_buff, block_end->line, ec+1 );
  1008.       my_memcpy( g_status.line_buff+ec+1, dest->line+rcol, lens );
  1009.       lens += ec + 1;
  1010.       g_status.line_buff_len = lens;
  1011.  
  1012.       temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), rc );
  1013.       if (*rc == OK) {
  1014.          temp_ll->line  = NULL;
  1015.          temp_ll->len   = 0;
  1016.          temp_ll->dirty = FALSE;
  1017.          g_status.copied = TRUE;
  1018.          *rc = un_copy_line( temp_ll, &d_w, TRUE );
  1019.  
  1020.          if (*rc == OK) {
  1021.             dest->next->prev = temp_ll;
  1022.             temp_ll->next = dest->next;
  1023.             dest->next = temp_ll;
  1024.             temp_ll->prev = dest;
  1025.          } else
  1026.             if (temp_ll != NULL)
  1027.                my_free( temp_ll );
  1028.       } else {
  1029.          if (temp_ll != NULL)
  1030.             my_free( temp_ll );
  1031.       }
  1032.  
  1033.       /*
  1034.        * file too big
  1035.        */
  1036.       if (*rc != OK)
  1037.          error( WARNING, window->bottom_line, dir3 );
  1038.  
  1039.       if (*rc == OK) {
  1040.          g_status.copied = FALSE;
  1041.          copy_line( dest );
  1042.          lens = block_start->len - bc;
  1043.  
  1044.          assert( lens >= 0 );
  1045.          assert( lens <= MAX_LINE_LENGTH );
  1046.          assert( bc >= 0 );
  1047.          assert( bc <= MAX_LINE_LENGTH );
  1048.          assert( rcol >= 0 );
  1049.  
  1050.          my_memcpy( g_status.line_buff+rcol, block_start->line+bc, lens );
  1051.          lens = rcol + lens;
  1052.          g_status.line_buff_len = lens;
  1053.          *rc = un_copy_line( dest, &d_w, TRUE );
  1054.       }
  1055.  
  1056.       source = block_start->next;
  1057.       for (li=br+1; li < er  &&  *rc == OK; li++) {
  1058.          lens = source->len;
  1059.          temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), rc );
  1060.  
  1061.          assert( lens >= 0 );
  1062.          assert( lens <= MAX_LINE_LENGTH );
  1063.  
  1064.          l = (text_ptr)my_malloc( lens * sizeof(char), rc );
  1065.          if (*rc == OK) {
  1066.             if (lens > 0)
  1067.                my_memcpy( l, source->line, lens );
  1068.             temp_ll->line  = l;
  1069.             temp_ll->len   = lens;
  1070.             temp_ll->dirty = TRUE;
  1071.  
  1072.             if (dest->next != NULL) {
  1073.                dest->next->prev = temp_ll;
  1074.                temp_ll->next = dest->next;
  1075.                dest->next = temp_ll;
  1076.                temp_ll->prev = dest;
  1077.             } else {
  1078.                temp_ll->next = dest;
  1079.                if (dest->prev != NULL)
  1080.                   dest->prev->next = temp_ll;
  1081.                temp_ll->prev = dest->prev;
  1082.                dest->prev = temp_ll;
  1083.                if (temp_ll->prev == NULL)
  1084.                   window->file_info->line_list = temp_ll;
  1085.             }
  1086.  
  1087.             dest = temp_ll;
  1088.             source = source->next;
  1089.          } else {
  1090.             /*
  1091.              * file too big
  1092.              */
  1093.             error( WARNING, window->bottom_line, dir3 );
  1094.             if (l != NULL)
  1095.                my_free( l );
  1096.             if (temp_ll != NULL)
  1097.                my_free( temp_ll );
  1098.             *rc = WARNING;
  1099.          }
  1100.       }
  1101.    } else if (action == MOVE) {
  1102.  
  1103.       /*
  1104.        * is the dest on the same line as the block_start?
  1105.        */
  1106.       if (ptoul( dest ) == ptoul( block_start )) {
  1107.  
  1108.          /*
  1109.           * move the text between rcol and bc in block_start->line
  1110.           *   to block_end->line + ec.
  1111.           */
  1112.          lens = bc - rcol;
  1113.          lend = block_end->len - (ec + 1);
  1114.          g_status.copied = FALSE;
  1115.          copy_line( block_end );
  1116.  
  1117.  
  1118.          assert( lens >= 0 );
  1119.          assert( lens <= MAX_LINE_LENGTH );
  1120.          assert( lend >= 0 );
  1121.          assert( lend <= MAX_LINE_LENGTH );
  1122.          assert( ec + lens + 1 <= MAX_LINE_LENGTH );
  1123.          assert( rcol >= 0 );
  1124.  
  1125.  
  1126.          my_memmove( g_status.line_buff + ec + lens + 1,
  1127.                      g_status.line_buff + ec + 1,  lend );
  1128.          my_memcpy( g_status.line_buff+ec+1, block_start->line+rcol, lens );
  1129.          g_status.line_buff_len = block_end->len + lens;
  1130.          *rc = un_copy_line( block_end, &d_w, TRUE );
  1131.  
  1132.          /*
  1133.           * now, remove the text between rcol and bc on block_start->line
  1134.           */
  1135.          if (*rc == OK) {
  1136.             lend = block_start->len - bc;
  1137.             copy_line( block_start );
  1138.  
  1139.             assert( lend >= 0 );
  1140.             assert( lend < MAX_LINE_LENGTH );
  1141.  
  1142.             my_memmove( g_status.line_buff + rcol,
  1143.                         g_status.line_buff + bc, lend );
  1144.  
  1145.             assert( block_start->len - (bc - rcol) >= 0 );
  1146.             assert( block_start->len - (bc - rcol) <= MAX_LINE_LENGTH );
  1147.  
  1148.             g_status.line_buff_len = block_start->len - (bc - rcol);
  1149.             *rc = un_copy_line( block_start, &d_w, TRUE );
  1150.          }
  1151.  
  1152.       /*
  1153.        * is the dest on the same line as the block_end?
  1154.        */
  1155.       } else if (ptoul( dest ) == ptoul( block_end )) {
  1156.  
  1157.          /*
  1158.           * move the text between rcol and ec on block_end->line to
  1159.           *   block_start->line + bc.
  1160.           */
  1161.          lens = rcol - ec;
  1162.          lend = block_start->len - bc;
  1163.          g_status.copied = FALSE;
  1164.          copy_line( block_start );
  1165.  
  1166.          assert( lens >= 0 );
  1167.          assert( lens <= MAX_LINE_LENGTH );
  1168.          assert( lend >= 0 );
  1169.          assert( lend <= MAX_LINE_LENGTH );
  1170.          assert( bc + lens <= MAX_LINE_LENGTH );
  1171.          assert( ec + 1 >= 0 );
  1172.  
  1173.          my_memmove( g_status.line_buff + bc + lens,
  1174.                      g_status.line_buff + bc,  lend );
  1175.          my_memcpy( g_status.line_buff+bc, block_end->line+ec+1, lens );
  1176.  
  1177.          assert( block_start->len + lens >= 0 );
  1178.          assert( block_start->len + lens <= MAX_LINE_LENGTH );
  1179.  
  1180.          g_status.line_buff_len = block_start->len + lens;
  1181.          *rc = un_copy_line( block_start, &d_w, TRUE );
  1182.  
  1183.          /*
  1184.           * now, remove the text on block_end->line between rcol and ec
  1185.           */
  1186.          if (*rc == OK) {
  1187.             lend = block_end->len - (rcol + 1);
  1188.             copy_line( block_end );
  1189.  
  1190.             assert( lend >= 0 );
  1191.             assert( lend <= MAX_LINE_LENGTH );
  1192.             assert( ec + 1 >= 0 );
  1193.             assert( rcol + 1 >= 0 );
  1194.             assert( ec + 1 <= MAX_LINE_LENGTH );
  1195.             assert( rcol + 1 <= MAX_LINE_LENGTH );
  1196.             assert( block_end->len - (rcol - ec) >= 0 );
  1197.             assert( block_end->len - (rcol - ec) <= MAX_LINE_LENGTH );
  1198.  
  1199.  
  1200.             my_memmove( g_status.line_buff + ec + 1,
  1201.                         g_status.line_buff + rcol + 1, lend );
  1202.             g_status.line_buff_len = block_end->len - (rcol - ec);
  1203.             *rc = un_copy_line( block_end, &d_w, TRUE );
  1204.          }
  1205.       } else {
  1206.  
  1207.          lens = dest->len - rcol;
  1208.  
  1209.          assert( ec + 1 >= 0 );
  1210.          assert( ec + 1 <= MAX_LINE_LENGTH );
  1211.          assert( lens >= 0 );
  1212.          assert( lens <= MAX_LINE_LENGTH );
  1213.          assert( rcol >= 0 );
  1214.          assert( rcol <= MAX_LINE_LENGTH );
  1215.  
  1216.          my_memcpy( g_status.line_buff, block_end->line, ec+1 );
  1217.          my_memcpy( g_status.line_buff+ec+1, dest->line+rcol, lens );
  1218.          lens += ec + 1;
  1219.          g_status.line_buff_len = lens;
  1220.  
  1221.          temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), rc );
  1222.          if (*rc == OK) {
  1223.             temp_ll->line  = NULL;
  1224.             temp_ll->len   = 0;
  1225.             temp_ll->dirty = FALSE;
  1226.             g_status.copied = TRUE;
  1227.             *rc = un_copy_line( temp_ll, &d_w, TRUE );
  1228.  
  1229.             if (*rc != ERROR) {
  1230.                dest->next->prev = temp_ll;
  1231.                temp_ll->next = dest->next;
  1232.                dest->next = temp_ll;
  1233.                temp_ll->prev = dest;
  1234.             } else
  1235.                if (temp_ll != NULL)
  1236.                   my_free( temp_ll );
  1237.          } else {
  1238.             if (temp_ll != NULL)
  1239.                my_free( temp_ll );
  1240.          }
  1241.  
  1242.          /*
  1243.           * file too big
  1244.           */
  1245.          if (*rc != OK)
  1246.             error( WARNING, window->bottom_line, dir3 );
  1247.  
  1248.          if (*rc == OK) {
  1249.             copy_line( dest );
  1250.             lens = block_start->len - bc;
  1251.  
  1252.             assert( bc >= 0 );
  1253.             assert( bc <= MAX_LINE_LENGTH );
  1254.             assert( lens >= 0 );
  1255.             assert( lens <= MAX_LINE_LENGTH );
  1256.             assert( rcol >= 0 );
  1257.             assert( rcol <= MAX_LINE_LENGTH );
  1258.  
  1259.             my_memcpy( g_status.line_buff+rcol, block_start->line+bc, lens );
  1260.             g_status.line_buff_len = lens + rcol;
  1261.             *rc = un_copy_line( dest, &d_w, TRUE );
  1262.             dest->dirty = TRUE;
  1263.          }
  1264.  
  1265.          if (*rc == OK  &&  ptoul( block_start->next ) != ptoul( block_end )) {
  1266.             block_start->next->prev = dest;
  1267.             temp_ll->prev = block_end->prev;
  1268.             block_end->prev->next = temp_ll;
  1269.             dest->next = block_start->next;
  1270.          }
  1271.  
  1272.          if (*rc == OK) {
  1273.             copy_line( block_start );
  1274.             detab_linebuff( );
  1275.             lend = bc;
  1276.             lens = block_end->len - (ec + 1);
  1277.  
  1278.             assert( bc >= 0 );
  1279.             assert( bc <= MAX_LINE_LENGTH );
  1280.             assert( lens >= 0 );
  1281.             assert( lens <= MAX_LINE_LENGTH );
  1282.             assert( lend >= 0 );
  1283.             assert( lend <= MAX_LINE_LENGTH );
  1284.             assert( ec + 1 >= 0 );
  1285.             assert( ec + 1 <= MAX_LINE_LENGTH );
  1286.             assert( lens + lend >= 0 );
  1287.             assert( lens + lend <= MAX_LINE_LENGTH );
  1288.  
  1289.             my_memcpy( g_status.line_buff+bc, block_end->line+ec+1, lens );
  1290.             g_status.line_buff_len = lend + lens;
  1291.             *rc = un_copy_line( block_start, &s_w, TRUE );
  1292.             block_start->dirty = TRUE;
  1293.             block_start->next = block_end->next;
  1294.             block_end->next->prev = block_start;
  1295.             if (block_end->line != NULL)
  1296.                my_free( block_end->line );
  1297.             my_free( block_end );
  1298.          }
  1299.       }
  1300.    } else if (action == DELETE) {
  1301.       copy_line( block_start );
  1302.       lens = block_end->len - (ec + 1);
  1303.  
  1304.       assert( bc >= 0 );
  1305.       assert( bc <= MAX_LINE_LENGTH );
  1306.       assert( lens >= 0 );
  1307.       assert( lens <= MAX_LINE_LENGTH );
  1308.       assert( ec + 1 >= 0 );
  1309.       assert( ec + 1 <= MAX_LINE_LENGTH );
  1310.       assert( bc + lens >= 0 );
  1311.       assert( bc + lens <= MAX_LINE_LENGTH );
  1312.  
  1313.       my_memcpy( g_status.line_buff+bc, block_end->line + ec+1, lens );
  1314.       g_status.line_buff_len = bc + lens;
  1315.       *rc = un_copy_line( block_start, &s_w, TRUE );
  1316.       block_start->dirty = TRUE;
  1317.       source = block_start->next;
  1318.       block_start->next = block_end->next;
  1319.       block_end->next->prev = block_start;
  1320.       block_end->next = NULL;
  1321.       while (source != NULL) {
  1322.          temp_ll = source;
  1323.          source = source->next;
  1324.          if (temp_ll->line != NULL)
  1325.             my_free( temp_ll->line );
  1326.          my_free( temp_ll );
  1327.       }
  1328.    }
  1329.  
  1330.    if (*rc == OK) {
  1331.       diff = er - br;
  1332.       if (action == COPY || action == KOPY || action == MOVE)
  1333.          dest_file->length += diff;
  1334.       if (action == DELETE || action == MOVE)
  1335.          source_file->length -= diff;
  1336.       if (action == DELETE && source_window->rline >= br) {
  1337.          source_window->rline -= diff;
  1338.          if (source_window->rline < br)
  1339.             source_window->rline = br;
  1340.       }
  1341.    }
  1342.  
  1343.    /*
  1344.     * restore all cursors in all windows
  1345.     */
  1346.    restore_cursors( dest_file );
  1347.    if (dest_file != source_file)
  1348.       restore_cursors( source_file );
  1349.    show_avail_mem( );
  1350. }
  1351.  
  1352.  
  1353. /*
  1354.  * Name:    do_box_block
  1355.  * Purpose: delete, move, copy, or kopy a BOX block
  1356.  * Date:    June 5, 1991
  1357.  * Passed:  window:         pointer to destination window (current window)
  1358.  *          source_window:  pointer to source window
  1359.  *          action:         block action  --  OVERLAY, FILL, etc...
  1360.  *          source_file:    pointer to source file structure
  1361.  *          dest_file:      pointer to destination file
  1362.  *          source:         pointer to source node
  1363.  *          dest:           pointer to destination node
  1364.  *          br:             beginning line number in marked block
  1365.  *          er:             ending line number in marked block
  1366.  *          block_inc:      increment used to number a block
  1367.  *          rline:          current line number in destination file
  1368.  *          block_num:      starting number when numbering a block
  1369.  *          block_just:     LEFT or RIGHT justified numbers in block
  1370.  *          fill_char:      character to fill a block
  1371.  *          same:           are source and destination files same? T or F
  1372.  *          block_len:      width of box block
  1373.  *          bc:             beginning column of block
  1374.  *          ec:             ending column of block
  1375.  *          rcol:           current column of cursor
  1376.  *          rc:             return code
  1377.  */
  1378. void do_box_block( TDE_WIN *window,  TDE_WIN *source_window,  int action,
  1379.                     file_infos *source_file,  file_infos *dest_file,
  1380.                     line_list_ptr source,  line_list_ptr dest, long br,
  1381.                     long er, long block_inc,
  1382.                     long rline, long block_num, int block_just, int fill_char,
  1383.                     int same, int block_len, int bc, int ec, int rcol, int *rc )
  1384. {
  1385. line_list_ptr p;                /* temporary list pointer */
  1386. int  lens;                      /* length of source line */
  1387. int  lend;                      /* length of destination line */
  1388. int  add;                       /* characters being added from another line */
  1389. char *block_buff;
  1390. char *swap_buff;
  1391. int  xbc, xec;                  /* temporary column variables */
  1392. long li;                        /* temporary line variables */
  1393. long dest_add;                  /* number of bytes added to destination file */
  1394. TDE_WIN s_w, d_w;       /* a couple of temporary TDE_WINs for BOX stuff */
  1395. int  padded_file;
  1396. TDE_WIN *w;
  1397.  
  1398.    padded_file = FALSE;
  1399.    dup_window_info( &s_w, source_window );
  1400.    dup_window_info( &d_w, window );
  1401.    s_w.rline   = br;
  1402.    s_w.ll      = source;
  1403.    s_w.visible = FALSE;
  1404.    d_w.rline   = rline;
  1405.    d_w.ll      = dest;
  1406.    d_w.visible = FALSE;
  1407.  
  1408.    block_buff = (char *)calloc( BUFF_SIZE + 2, sizeof(char) );
  1409.    swap_buff  = (char *)calloc( BUFF_SIZE + 2, sizeof(char) );
  1410.    if (block_buff == NULL || swap_buff == NULL) {
  1411.       error( WARNING, window->bottom_line, block4 );
  1412.       *rc = ERROR;
  1413.    }
  1414.  
  1415.    /*
  1416.     * special case for block actions.  since block actions always
  1417.     *   move forward thru the file, overlapping text in an OVERLAY
  1418.     *   action don't do right.  make the operation start at the end
  1419.     *   of the block and work backwards.
  1420.     */
  1421.    if (*rc == OK  &&  (action == OVERLAY || action == SWAP) &&
  1422.            same  &&  rline > br  &&  rline <= er) {
  1423.  
  1424.       /*
  1425.        * see if we need to add padd lines at eof.
  1426.        */
  1427.       dest_add = rline - br;
  1428.       if (dest_add + er > window->file_info->length) {
  1429.          dest_add = dest_add - (window->file_info->length - er);
  1430.          p = dest_file->line_list_end->prev;
  1431.          for (; dest_add > 0  &&  *rc == OK; dest_add--)
  1432.             *rc = pad_dest_line( window, dest_file, p );
  1433.          padded_file = TRUE;
  1434.       }
  1435.  
  1436.       /*
  1437.        * move source and dest pointers to the end of the OVERLAY
  1438.        */
  1439.       for (li=er-br; li > 0; li--) {
  1440.          load_undo_buffer( dest_file, dest->line, dest->len );
  1441.          dest = dest->next;
  1442.          ++d_w.rline;
  1443.          source = source->next;
  1444.          ++s_w.rline;
  1445.       }
  1446.  
  1447.       /*
  1448.        * work backwards so the overlapped OVERLAY block don't use
  1449.        * overlayed text to fill the block.  same for SWAPPing blocks.
  1450.        */
  1451.       for (li=er; *rc == OK  &&  li >= br  &&  !g_status.control_break;
  1452.                                        li--, s_w.rline--, d_w.rline--) {
  1453.          lens = find_end( source->line, source->len );
  1454.          lend = find_end( dest->line, dest->len );
  1455.          if (lens != 0 || lend != 0) {
  1456.             load_box_buff( block_buff, source, bc, ec, ' ' );
  1457.             if (action == SWAP)
  1458.                load_box_buff( swap_buff, dest, rcol, rcol+block_len, ' ' );
  1459.             *rc = copy_buff_2file( &d_w, block_buff, dest, rcol,
  1460.                                     block_len, action );
  1461.             dest->dirty = TRUE;
  1462.             if (action == SWAP) {
  1463.                add = 0;
  1464.                *rc = copy_buff_2file( &s_w, swap_buff, source, bc,
  1465.                                 block_len, action );
  1466.                source->dirty = TRUE;
  1467.             }
  1468.          }
  1469.          source = source->prev;
  1470.          dest = dest->prev;
  1471.       }
  1472.    } else {
  1473.       if (action == FILL)
  1474.          block_fill( block_buff, fill_char, block_len );
  1475.       for (li=br; *rc == OK  &&  li <= er  &&  !g_status.control_break;
  1476.                            li++, s_w.rline++, d_w.rline++) {
  1477.          lens = find_end( source->line, source->len );
  1478.          lend = find_end( dest->line, dest->len );
  1479.  
  1480.          switch (action) {
  1481.             case FILL    :
  1482.             case NUMBER  :
  1483.             case DELETE  :
  1484.             case MOVE    :
  1485.                load_undo_buffer( source_file, source->line, source->len );
  1486.                break;
  1487.             case COPY    :
  1488.             case KOPY    :
  1489.             case OVERLAY :
  1490.                load_undo_buffer( dest_file, dest->line, dest->len );
  1491.                break;
  1492.          }
  1493.  
  1494.          /*
  1495.           * with FILL and NUMBER operations, we're just adding chars
  1496.           *   to the file at the source location.  we don't have to
  1497.           *   worry about bookkeeping.
  1498.           */
  1499.          if (action == FILL || action == NUMBER) {
  1500.             if (action == NUMBER) {
  1501.               number_block_buff( block_buff, block_len, block_num, block_just );
  1502.               block_num += block_inc;
  1503.             }
  1504.             *rc = copy_buff_2file( &s_w, block_buff, source, rcol,
  1505.                                 block_len, action );
  1506.             source->dirty = TRUE;
  1507.  
  1508.          /*
  1509.           * if we are doing a BOX action and both the source and
  1510.           * destination are 0 then we have nothing to do.
  1511.           */
  1512.          } else if (lens != 0 || lend != 0) {
  1513.  
  1514.             /*
  1515.              * do actions that may require adding to file
  1516.              */
  1517.             if (action == MOVE     ||  action == COPY || action == KOPY ||
  1518.                 action == OVERLAY  ||  action == SWAP) {
  1519.                xbc = bc;
  1520.                xec = ec;
  1521.                if (action != OVERLAY  &&  action != SWAP  &&  same) {
  1522.                   if (rcol < bc && rline > br && rline <=er)
  1523.                      if (li >= rline) {
  1524.                         xbc = bc + block_len;
  1525.                         xec = ec + block_len;
  1526.                      }
  1527.                }
  1528.                load_box_buff( block_buff, source, xbc, xec, ' ' );
  1529.                if (action == SWAP)
  1530.                   load_box_buff( swap_buff, dest, rcol, rcol+block_len, ' ' );
  1531.                *rc = copy_buff_2file( &d_w, block_buff, dest, rcol,
  1532.                                 block_len, action );
  1533.                dest->dirty = TRUE;
  1534.                if (action == SWAP && *rc == OK) {
  1535.                   *rc = copy_buff_2file( &s_w, swap_buff, source, xbc,
  1536.                                    block_len, action );
  1537.                   source->dirty = TRUE;
  1538.                }
  1539.             }
  1540.  
  1541.             /*
  1542.              * do actions that may require deleting from file
  1543.              */
  1544.             if (action == MOVE || action == DELETE) {
  1545.                lens = find_end( source->line, source->len );
  1546.                if (lens >= (bc + 1)) {
  1547.                   source->dirty = TRUE;
  1548.                   add = block_len;
  1549.                   xbc = bc;
  1550.                   if (lens <= (ec + 1))
  1551.                      add = lens - bc;
  1552.                   if (same && action == MOVE) {
  1553.                      if (rcol < bc && rline >= br && rline <=er)
  1554.                         if (li >= rline) {
  1555.                            xbc = bc + block_len;
  1556.                            if (lens <= (ec + block_len + 1))
  1557.                               add = lens - xbc;
  1558.                         }
  1559.                   }
  1560.                   if (add > 0)
  1561.                      *rc = delete_box_block( &s_w, source, xbc, add );
  1562.                }
  1563.             }
  1564.          }
  1565.  
  1566.          /*
  1567.           * if we are doing any BOX action we need to move the source pointer
  1568.           * to the next line.
  1569.           */
  1570.          source = source->next;
  1571.  
  1572.          /*
  1573.           * if we are doing any action other than DELETE, we need to move
  1574.           * the destination to the next line in marked block.
  1575.           * In BOX mode, we may need to pad the end of the file
  1576.           * with a blank line before we process the next line.
  1577.           */
  1578.          if (action != DELETE && action != FILL && action != NUMBER) {
  1579.             p = dest->next;
  1580.             if (p->len != EOF)
  1581.                dest = p;
  1582.             else if (li < er) {
  1583.                padded_file = TRUE;
  1584.                pad_dest_line( window, dest_file, p );
  1585.                dest = dest->next;
  1586.             }
  1587.          }
  1588.       }
  1589.    }
  1590.    if (block_buff != NULL)
  1591.       free( block_buff );
  1592.    if (swap_buff != NULL)
  1593.       free( swap_buff );
  1594.    if (padded_file) {
  1595.       w = g_status.window_list;
  1596.       while (w != NULL) {
  1597.          if (w->file_info == dest_file  &&  w->visible)
  1598.             show_size( w );
  1599.          w = w->next;
  1600.       }
  1601.    }
  1602.    show_avail_mem( );
  1603. }
  1604.  
  1605.  
  1606. /*
  1607.  * Name:    load_box_buff
  1608.  * Class:   helper function
  1609.  * Purpose: copy the contents of a BOX to a block buffer.
  1610.  * Date:    June 5, 1991
  1611.  * Passed:  block_buff: local buffer for block moves
  1612.  *          ll:         node to source line in file to load
  1613.  *          bc:     beginning column of BOX. used only in BOX operations.
  1614.  *          ec:     ending column of BOX. used only in BOX operations.
  1615.  *          filler: character to fill boxes that end past eol
  1616.  * Notes:   For BOX blocks, there are several things to take care of:
  1617.  *            1) The BOX begins and ends within a line - just copy the blocked
  1618.  *            characters to the block buff.  2) the BOX begins within a line
  1619.  *            but ends past the eol - copy all the characters within the line
  1620.  *            to the block buff then fill with padding.  3) the BOX begins and
  1621.  *            ends past eol - fill entire block buff with padding (filler).
  1622.  *          the fill character varies with the block operation.  for sorting
  1623.  *            a box block, the fill character is '\0'.  for adding text to
  1624.  *            the file, the fill character is a space.
  1625.  */
  1626. void load_box_buff( char *block_buff, line_list_ptr ll, int bc, int ec,
  1627.                     char filler )
  1628. {
  1629. int len;
  1630. int avlen;
  1631. register int i;
  1632. register char *bb;
  1633. text_ptr s;
  1634.  
  1635.    assert( bc >= 0 );
  1636.    assert( ec >= bc );
  1637.    assert( ec < MAX_LINE_LENGTH );
  1638.  
  1639.    bb = block_buff;
  1640.    len = ll->len;
  1641.    s = detab_a_line( ll->line, &len );
  1642.    /*
  1643.     * block start may be past eol
  1644.     */
  1645.    if (len < ec + 1) {
  1646.       /*
  1647.        * does block start past eol? - fill with pad
  1648.        */
  1649.       assert( ec + 1 - bc >= 0 );
  1650.  
  1651.       memset( block_buff, filler, (ec + 1) - bc );
  1652.       if (len >= bc) {
  1653.          /*
  1654.           * block ends past eol - fill with pad
  1655.           */
  1656.          avlen = len - bc;
  1657.          s += bc;
  1658.          for (i=avlen; i>0; i--)
  1659.             *bb++ = *s++;
  1660.       }
  1661.    } else {
  1662.       /*
  1663.        * block is within line - copy block to buffer
  1664.        */
  1665.       avlen = (ec + 1) - bc;
  1666.       s = s + bc;
  1667.       for (i=avlen; i>0; i--)
  1668.          *bb++ = *s++;
  1669.    }
  1670. }
  1671.  
  1672.  
  1673. /*
  1674.  * Name:    copy_buff_2file
  1675.  * Class:   helper function
  1676.  * Purpose: copy the contents of block buffer to destination file
  1677.  * Date:    June 5, 1991
  1678.  * Passed:  window:     pointer to current window
  1679.  *          block_buff: local buffer for moves
  1680.  *          dest:       pointer to destination line in destination file
  1681.  *          rcol:       if in BOX mode, destination column in destination file
  1682.  *          block_len:  if in BOX mode, width of block to copy
  1683.  *          action:     type of block action
  1684.  * Notes:   In BOX mode, the destination line has already been prepared.
  1685.  *          Just copy the BOX buffer to the destination line.
  1686.  */
  1687. int  copy_buff_2file( TDE_WIN *window, char *block_buff, line_list_ptr dest,
  1688.                       int rcol, int block_len, int action )
  1689. {
  1690. char *s;
  1691. char *d;
  1692. int len;
  1693. int pad;
  1694. int add;
  1695.  
  1696.    copy_line( dest );
  1697.    if (mode.inflate_tabs)
  1698.       detab_linebuff( );
  1699.  
  1700.    len = g_status.line_buff_len;
  1701.  
  1702.    assert( len >= 0 );
  1703.    assert( len < MAX_LINE_LENGTH );
  1704.    assert( rcol >= 0 );
  1705.    assert( rcol < MAX_LINE_LENGTH );
  1706.    assert( block_len >= 0 );
  1707.    assert( block_len < BUFF_SIZE );
  1708.  
  1709.    if (rcol > len) {
  1710.       pad = rcol - len;
  1711.  
  1712.       assert( pad >= 0 );
  1713.       assert( pad < MAX_LINE_LENGTH );
  1714.  
  1715.       memset( g_status.line_buff + len, ' ', pad );
  1716.       len += pad;
  1717.    }
  1718.  
  1719.    s = g_status.line_buff + rcol;
  1720.  
  1721.    /*
  1722.     * s is pointing to location to perform BOX operation.  If we do a
  1723.     * FILL or OVERLAY, we do not necessarily add any extra space.  If the
  1724.     * line does not extend all the thru the BOX then we add.
  1725.     * we always add space when we COPY, KOPY, or MOVE
  1726.     */
  1727.    if (action == FILL || action == OVERLAY || action == NUMBER || action == SWAP) {
  1728.       add = len - rcol;
  1729.       if (add < block_len) {
  1730.          pad = block_len - add;
  1731.  
  1732.          assert( pad >= 0 );
  1733.          assert( pad < MAX_LINE_LENGTH );
  1734.  
  1735.          memset( g_status.line_buff + len, ' ', pad );
  1736.          len += pad;
  1737.       }
  1738.    } else {
  1739.       d = s + block_len;
  1740.       add = len - rcol;
  1741.  
  1742.       assert( add >= 0 );
  1743.       assert( add < MAX_LINE_LENGTH );
  1744.  
  1745.       memmove( d, s, add );
  1746.       len += block_len;
  1747.    }
  1748.  
  1749.    assert( rcol + block_len <= len );
  1750.    assert( len >= 0 );
  1751.    assert( len < MAX_LINE_LENGTH );
  1752.  
  1753.    memmove( s, block_buff, block_len );
  1754.    g_status.line_buff_len = len;
  1755.    if (mode.inflate_tabs)
  1756.       entab_linebuff( );
  1757.    return( un_copy_line( dest, window, TRUE ) );
  1758. }
  1759.  
  1760.  
  1761. /*
  1762.  * Name:    block_fill
  1763.  * Class:   helper function
  1764.  * Purpose: fill the block buffer with character
  1765.  * Date:    June 5, 1991
  1766.  * Passed:  block_buff: local buffer for moves
  1767.  *          fill_char:  fill character
  1768.  *          block_len:  number of columns in block
  1769.  * Notes:   Fill block_buffer for block_len characters using fill_char.  This
  1770.  *          function is used only for BOX blocks.
  1771.  */
  1772. void block_fill( char *block_buff, int fill_char, int block_len )
  1773. {
  1774.    assert( block_len >= 0 );
  1775.    assert( block_len < BUFF_SIZE );
  1776.    assert( block_buff != NULL );
  1777.  
  1778.    memset( block_buff, fill_char, block_len );
  1779. }
  1780.  
  1781.  
  1782. /*
  1783.  * Name:    number_block_buff
  1784.  * Class:   helper function
  1785.  * Purpose: put a number into the block buffer
  1786.  * Date:    June 5, 1991
  1787.  * Passed:  block_buff: local buffer for moves
  1788.  *          block_len:  number of columns in block
  1789.  *          block_num:  long number to fill block
  1790.  *          just:       LEFT or RIGHT justified?
  1791.  * Notes:   Fill block_buffer for block_len characters with number.
  1792.  *          This function is used only for BOX blocks.
  1793.  */
  1794. void number_block_buff( char *block_buff, int block_len, long block_num,
  1795.                         int just )
  1796. {
  1797. int len;                /* length of number buffer */
  1798. int i;
  1799. char temp[MAX_COLS+2];
  1800.  
  1801.    assert( block_len >= 0 );
  1802.    assert( block_len < BUFF_SIZE );
  1803.  
  1804.    block_fill( block_buff, ' ', block_len );
  1805.    len = strlen( my_ltoa( block_num, temp, 10 ) );
  1806.    if (just == RIGHT) {
  1807.       block_len--;
  1808.       len--;
  1809.       for (;block_len >= 0 && len >= 0; block_len--, len--)
  1810.          block_buff[block_len] = temp[len];
  1811.    } else {
  1812.       for (i=0; block_len > 0 && i < len; block_len--, i++)
  1813.          block_buff[i] = temp[i];
  1814.    }
  1815. }
  1816.  
  1817.  
  1818. /*
  1819.  * Name:    restore_cursors
  1820.  * Class:   helper function
  1821.  * Purpose: a file has been modified - must restore all cursor pointers
  1822.  * Date:    June 5, 1991
  1823.  * Passed:  file:  pointer to file with changes
  1824.  * Notes:   Go through the window list and adjust the cursor pointers
  1825.  *          as needed.
  1826.  */
  1827. void restore_cursors( file_infos *file )
  1828. {
  1829. register TDE_WIN *window;
  1830. line_list_ptr ll;
  1831. long n;
  1832.  
  1833.    assert( file != NULL );
  1834.  
  1835.    window = g_status.window_list;
  1836.    while (window != NULL) {
  1837.       if (window->file_info == file) {
  1838.          window->bin_offset = 0;
  1839.          if (window->rline < 1L)
  1840.             window->rline = 1L;
  1841.          if (window->rline > file->length)
  1842.             window->rline = file->length;
  1843.          ll = file->line_list;
  1844.          n = 1L;
  1845.          for (; n < window->rline; n++) {
  1846.             window->bin_offset += ll->len;
  1847.             ll = ll->next;
  1848.          }
  1849.          window->ll = ll;
  1850.          if (window->rline < (window->cline - (window->top_line+window->ruler-1)))
  1851.             window->cline = (int)window->rline + window->top_line+window->ruler-1;
  1852.          if (window->cline < window->top_line + window->ruler)
  1853.             window->cline = window->top_line + window->ruler;
  1854.          if (window->visible)
  1855.             show_size( window );
  1856.       }
  1857.       window = window->next;
  1858.    }
  1859. }
  1860.  
  1861.  
  1862. /*
  1863.  * Name:    delete_box_block
  1864.  * Class:   helper function
  1865.  * Purpose: delete the marked text
  1866.  * Date:    June 5, 1991
  1867.  * Passed:  s_w:    source window
  1868.  *          source: pointer to line with block to delete
  1869.  *          bc:     beginning column of block - BOX mode only
  1870.  *          add:    number of characters in block to delete
  1871.  * Notes:   Used only for BOX blocks.  Delete the block.
  1872.  */
  1873. int  delete_box_block( TDE_WIN *s_w, line_list_ptr source, int bc, int add )
  1874. {
  1875. char *s;
  1876. int number;
  1877.  
  1878.    assert( s_w != NULL );
  1879.    assert( source != NULL );
  1880.    assert( bc >= 0 );
  1881.    assert( bc < MAX_LINE_LENGTH );
  1882.    assert( add >= 0 );
  1883.    assert( add < MAX_LINE_LENGTH );
  1884.  
  1885.    copy_line( source );
  1886.    detab_linebuff( );
  1887.    number = g_status.line_buff_len - bc;
  1888.    s = g_status.line_buff + bc + add;
  1889.  
  1890.    assert( number >= 0 );
  1891.    assert( number < MAX_LINE_LENGTH );
  1892.    assert( bc + add >= 0 );
  1893.    assert( bc + add < MAX_LINE_LENGTH );
  1894.    assert( add <= g_status.line_buff_len );
  1895.  
  1896.    memmove( s - add, s, number );
  1897.    g_status.line_buff_len -= add;
  1898.    entab_linebuff( );
  1899.    return( un_copy_line( source, s_w, TRUE ) );
  1900. }
  1901.  
  1902.  
  1903. /*
  1904.  * Name:    check_block
  1905.  * Class:   helper function
  1906.  * Purpose: To check that the block is still valid.
  1907.  * Date:    June 5, 1991
  1908.  * Notes:   After some editing, the marked block may not be valid.  For example,
  1909.  *          deleting all the lines in a block in another window.  We don't
  1910.  *          need to keep up with the block text pointers while doing normal
  1911.  *          editing; however, we need to refresh them before doing block stuff.
  1912.  */
  1913. void check_block( void )
  1914. {
  1915. register file_infos *file;
  1916. TDE_WIN filler;
  1917.  
  1918.    file = g_status.marked_file;
  1919.    if (file == NULL || file->block_br > file->length)
  1920.       unmark_block( &filler );
  1921.    else {
  1922.       if (file->block_er > file->length)
  1923.          file->block_er = file->length;
  1924.       find_begblock( file );
  1925.       find_endblock( file );
  1926.    }
  1927. }
  1928.  
  1929.  
  1930. /*
  1931.  * Name:    find_begblock
  1932.  * Class:   helper editor function
  1933.  * Purpose: find the beginning line in file with marked block
  1934.  * Date:    June 5, 1991
  1935.  * Passed:  file: file containing marked block
  1936.  * Notes:   file->block_start contains starting line of marked block.
  1937.  */
  1938. void find_begblock( file_infos *file )
  1939. {
  1940. line_list_ptr ll;
  1941. long li;           /* line counter (long i) */
  1942.  
  1943.    assert( file != NULL );
  1944.    assert( file->line_list != NULL );
  1945.  
  1946.    ll = file->line_list;
  1947.    for (li=1; li<file->block_br && ll->next != NULL; li++)
  1948.       ll = ll->next;
  1949.  
  1950.    file->block_start = ll;
  1951. }
  1952.  
  1953.  
  1954. /*
  1955.  * Name:    find_endblock
  1956.  * Class:   helper function
  1957.  * Purpose: find the ending line in file with marked block
  1958.  * Date:    June 5, 1991
  1959.  * Passed:  file: file containing marked block
  1960.  * Notes:   If in LINE mode, file->block_end is set to end of line of last
  1961.  *          line in block.  If in BOX mode, file->block_end is set to
  1962.  *          beginning of last line in marked block.  If the search for the
  1963.  *          ending line of the marked block goes past the eof, set the
  1964.  *          ending line of the block to the last line in the file.
  1965.  */
  1966. void find_endblock( file_infos *file )
  1967. {
  1968. line_list_ptr ll; /* start from beginning of file and go to end */
  1969. long i;           /* line counter */
  1970. register file_infos *fp;
  1971.  
  1972.    assert( file != NULL );
  1973.    assert( file->block_start != NULL );
  1974.  
  1975.    fp = file;
  1976.    ll = fp->block_start;
  1977.    if (ll != NULL) {
  1978.       for (i=fp->block_br;  i < fp->block_er && ll->next != NULL; i++)
  1979.          ll = ll->next;
  1980.       if (ll != NULL)
  1981.          fp->block_end = ll;
  1982.       else {
  1983.  
  1984.          /*
  1985.           * last line in marked block is NULL.  if LINE block, set end to
  1986.           * last character in the file.  if STREAM or BOX block, set end to
  1987.           * start of last line in file.  ending row, or er, is then set to
  1988.           * file length.
  1989.           */
  1990.          fp->block_end = fp->line_list_end->prev;
  1991.          fp->block_er = fp->length;
  1992.       }
  1993.    }
  1994. }
  1995.  
  1996.  
  1997. /*
  1998.  * Name:    block_write
  1999.  * Class:   primary editor function
  2000.  * Purpose: To write the currently marked block to a disk file.
  2001.  * Date:    June 5, 1991
  2002.  * Passed:  window:  pointer to current window
  2003.  * Notes:   If the file already exists, the user gets to choose whether
  2004.  *           to overwrite or append.
  2005.  */
  2006. int  block_write( TDE_WIN *window )
  2007. {
  2008. int prompt_line;
  2009. int rc;
  2010. file_infos *file;
  2011. int block_type;
  2012. char temp[MAX_COLS+2];
  2013. #if defined( __UNIX__ )
  2014.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  2015.  mode_t fattr;
  2016. #else
  2017.  char display_buff[(MAX_COLS+2)*2];
  2018.  int fattr;
  2019. #endif
  2020.  
  2021.    /*
  2022.     * make sure block is marked OK
  2023.     */
  2024.    entab_linebuff( );
  2025.    rc = un_copy_line( window->ll, window, TRUE );
  2026.  
  2027.    check_block( );
  2028.    if (rc == OK  &&  g_status.marked == TRUE) {
  2029.       prompt_line = window->bottom_line;
  2030.       file        = g_status.marked_file;
  2031.  
  2032.       assert( file != NULL );
  2033.  
  2034.       block_type  = file->block_type;
  2035.  
  2036.       /*
  2037.        * find out which file to write to
  2038.        */
  2039.  
  2040.       save_screen_line( 0, prompt_line, display_buff );
  2041.       *g_status.rw_name = '\0';
  2042.       if (get_name( block6, prompt_line, g_status.rw_name,
  2043.                     g_display.message_color ) == OK) {
  2044.          /*
  2045.           * if the file exists, find out whether to overwrite or append
  2046.           */
  2047.          rc = get_fattr( g_status.rw_name, &fattr );
  2048.          if (rc == OK) {
  2049.             /*
  2050.              * file exists. overwrite or append?
  2051.              */
  2052.             set_prompt( block7, prompt_line );
  2053.             switch (get_oa( )) {
  2054.                case A_OVERWRITE :
  2055.                   change_mode( g_status.rw_name, prompt_line );
  2056.                   /*
  2057.                    * writing block to
  2058.                    */
  2059.                   combine_strings( temp, block8, g_status.rw_name, "'" );
  2060.                   s_output( temp, prompt_line, 0, g_display.message_color );
  2061.  
  2062. #if defined( __UNIX__ )
  2063.                   refresh( );
  2064. #endif
  2065.  
  2066.                   rc = hw_save( g_status.rw_name, file, file->block_br,
  2067.                                 file->block_er, block_type );
  2068.                   if (rc == ERROR)
  2069.                      /*
  2070.                       * could not write block
  2071.                       */
  2072.                      error( WARNING, prompt_line, block9 );
  2073.                   break;
  2074.                case A_APPEND :
  2075.                   /*
  2076.                    * appending block to
  2077.                    */
  2078.                   combine_strings( temp, block10, g_status.rw_name, "'" );
  2079.                   s_output( temp, prompt_line, 0, g_display.message_color );
  2080.  
  2081. #if defined( __UNIX__ )
  2082.                   refresh( );
  2083. #endif
  2084.  
  2085.                   rc = hw_append( g_status.rw_name, file, file->block_br,
  2086.                                   file->block_er, block_type );
  2087.                   if (rc == ERROR)
  2088.                      /*
  2089.                       * could not append block
  2090.                       */
  2091.                      error( WARNING, prompt_line, block11 );
  2092.                   break;
  2093.                case AbortCommand :
  2094.                default :
  2095.                   rc = ERROR;
  2096.                   break;
  2097.             }
  2098.          } else if (rc != ERROR) {
  2099.             /*
  2100.              * writing block to
  2101.              */
  2102.             combine_strings( temp, block12, g_status.rw_name, "'" );
  2103.             s_output( temp, prompt_line, 0, g_display.message_color );
  2104.  
  2105. #if defined( __UNIX__ )
  2106.                   refresh( );
  2107. #endif
  2108.  
  2109.             if (hw_save( g_status.rw_name, file, file->block_br, file->block_er,
  2110.                          block_type ) == ERROR) {
  2111.                /*
  2112.                 * could not write block
  2113.                 */
  2114.                error( WARNING, prompt_line, block9 );
  2115.                rc = ERROR;
  2116.             }
  2117.          }
  2118.       }
  2119.       restore_screen_line( 0, prompt_line, display_buff );
  2120.    } else
  2121.       rc = ERROR;
  2122.    return( rc );
  2123. }
  2124.  
  2125.  
  2126. /*
  2127.  * Name:     block_print
  2128.  * Class:    primary editor function
  2129.  * Purpose:  Print an entire file or the currently marked block.
  2130.  * Date:     June 5, 1991
  2131.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  2132.  * Passed:   window:  pointer to current window
  2133.  * Notes:    With the added Critical Error Handler routine, let's fflush
  2134.  *           the print buffer first.
  2135.  */
  2136. int  block_print( TDE_WIN *window )
  2137. {
  2138. int  col;
  2139. int  func;
  2140. int  prompt_line;
  2141. line_list_ptr block_start;   /* start of block in file */
  2142. file_infos *file;
  2143. int  block_type;
  2144. char *p;
  2145. int  len;
  2146. int  bc;
  2147. int  ec;
  2148. int  last_c;
  2149. long lbegin;
  2150. long lend;
  2151. long l;
  2152. int  color;
  2153. int  rc;
  2154. char answer[MAX_COLS+2];
  2155. #if defined( __UNIX__ )
  2156.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  2157. #else
  2158.  char display_buff[(MAX_COLS+2)*2];
  2159. #endif
  2160.  
  2161.    color = g_display.message_color;
  2162.    entab_linebuff( );
  2163.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2164.       return( ERROR );
  2165.    rc = OK;
  2166.  
  2167.    prompt_line = window->bottom_line;
  2168.    save_screen_line( 0, prompt_line, display_buff );
  2169.    /*
  2170.     * print entire file or just marked block?
  2171.     */
  2172.  
  2173.    assert( strlen( block13 ) < (size_t)g_display.ncols );
  2174.  
  2175.    strcpy( answer, block13 );
  2176.    col = strlen( answer );
  2177.    s_output( answer, prompt_line, 0, color );
  2178.    eol_clear( col, prompt_line, g_display.text_color );
  2179.    xygoto( col, prompt_line );
  2180.    func = col = 0;
  2181.    while (col != L_FILE  &&  col != L_BLOCK  &&  func != AbortCommand) {
  2182.       col = getanswerkey( );
  2183.       func = getfunc( col );
  2184.       if (col == ESC  ||  func == AbortCommand)
  2185.          rc = ERROR;
  2186.    }
  2187.  
  2188.    if (rc == OK) {
  2189.       /*
  2190.        * if everything is everything, flush the printer before we start
  2191.        *   printing.  then, check the critical error flag after the flush.
  2192.        */
  2193.       fflush( my_stdprn );
  2194.       if (ceh.flag == ERROR)
  2195.          rc = ERROR;
  2196.    }
  2197.  
  2198.    if (rc != ERROR) {
  2199.       file = window->file_info;
  2200.       block_type  = NOTMARKED;
  2201.       lend =  l = file->length;
  2202.       block_start = file->line_list;
  2203.  
  2204.       if (col == L_FILE)
  2205.          block_start = file->line_list;
  2206.       else {
  2207.          check_block( );
  2208.          if (g_status.marked == TRUE) {
  2209.             file        = g_status.marked_file;
  2210.             block_start = file->block_start;
  2211.             block_type  = file->block_type;
  2212.             lend =   l  = file->block_er + 1l - file->block_br;
  2213.          } else
  2214.             rc = ERROR;
  2215.       }
  2216.  
  2217.       if (rc != ERROR) {
  2218.          eol_clear( 0, prompt_line, color );
  2219.          /*
  2220.           * printing line   of    press control-break to cancel.
  2221.           */
  2222.          s_output( block14, prompt_line, 0, color );
  2223.          my_ltoa( l, answer, 10 );
  2224.          s_output( answer, prompt_line, 25, color );
  2225.          xygoto( BLOCK14_LINE_SLOT, prompt_line );
  2226.  
  2227.          /*
  2228.           * bc and ec are used only in BOX and STREAM blocks.
  2229.           * last_c is last column in a BOX block
  2230.           */
  2231.          bc = file->block_bc;
  2232.          ec = file->block_ec;
  2233.          last_c = ec + 1 - bc;
  2234.  
  2235.          p = g_status.line_buff;
  2236.          lbegin = 1;
  2237.          for (col=OK; l>0 && col == OK && !g_status.control_break; l--) {
  2238.             my_ltoa( lbegin, answer, 10 );
  2239.             s_output( answer, prompt_line, BLOCK14_LINE_SLOT, color );
  2240.             g_status.copied = FALSE;
  2241.             if (block_type == BOX) {
  2242.                load_box_buff( p, block_start, bc, ec, ' ' );
  2243.                len = last_c;
  2244.             } else if (block_type == STREAM && lbegin == 1) {
  2245.                len = block_start->len;
  2246.                detab_a_line( block_start->line, &len );
  2247.                if (bc > len)
  2248.                   len = 0;
  2249.                else {
  2250.                   if (lbegin == lend) {
  2251.                      load_box_buff( p, block_start, bc, ec, ' ' );
  2252.                      len = last_c;
  2253.                   } else {
  2254.                      len = len - bc;
  2255.                      g_status.copied = TRUE;
  2256.  
  2257.                      assert( len >= 0 );
  2258.                      assert( len < MAX_LINE_LENGTH );
  2259.  
  2260.                      my_memcpy( p, block_start->line + bc, len );
  2261.                   }
  2262.                }
  2263.             } else if (block_type == STREAM && l == 1L) {
  2264.                copy_line( block_start );
  2265.                detab_linebuff( );
  2266.                len = g_status.line_buff_len;
  2267.                if (len > ec + 1)
  2268.                   len = ec + 1;
  2269.             } else {
  2270.                copy_line( block_start );
  2271.                len = g_status.line_buff_len;
  2272.             }
  2273.  
  2274.             assert( len >= 0 );
  2275.             assert( len < MAX_LINE_LENGTH );
  2276.  
  2277.             *(p+len) = '\r';
  2278.             ++len;
  2279.             *(p+len) = '\n';
  2280.             ++len;
  2281.             if (fwrite( p, sizeof( char ), len, my_stdprn ) < (unsigned)len ||
  2282.                 ceh.flag == ERROR)
  2283.                col = ERROR;
  2284.             block_start = block_start->next;
  2285.             ++lbegin;
  2286.          }
  2287.          g_status.copied = FALSE;
  2288.          if (ceh.flag != ERROR)
  2289.             fflush( my_stdprn );
  2290.          else
  2291.             rc = ERROR;
  2292.       }
  2293.    }
  2294.    g_status.copied = FALSE;
  2295.    restore_screen_line( 0, prompt_line, display_buff );
  2296.    return( rc );
  2297. }
  2298.  
  2299.  
  2300. /*
  2301.  * Name:    get_block_fill_char
  2302.  * Class:   helper function
  2303.  * Purpose: get the character to fill marked block.
  2304.  * Date:    June 5, 1991
  2305.  * Passed:  window:  pointer to current window
  2306.  *          c: address of character to fill block
  2307.  */
  2308. int  get_block_fill_char( TDE_WIN *window, int *c )
  2309. {
  2310. register int col;
  2311. int prompt_line;
  2312. int rc;
  2313. char answer[MAX_COLS+2];
  2314. #if defined( __UNIX__ )
  2315.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  2316. #else
  2317.  char display_buff[(MAX_COLS+2)*2];
  2318. #endif
  2319.  
  2320.    rc = OK;
  2321.    prompt_line = window->bottom_line;
  2322.    save_screen_line( 0, prompt_line, display_buff );
  2323.    /*
  2324.     * enter character to fill block (esc to exit)
  2325.     */
  2326.  
  2327.    assert( strlen( block15 ) < (size_t)g_display.ncols );
  2328.  
  2329.    strcpy( answer, block15 );
  2330.    s_output( answer, prompt_line, 0, g_display.message_color );
  2331.    col = strlen( answer );
  2332.    eol_clear( col, prompt_line, g_display.text_color );
  2333.    xygoto( col, prompt_line );
  2334.    col = getkey( );
  2335.    if (col >= 256)
  2336.       rc = ERROR;
  2337.    else
  2338.       *c = col;
  2339.    restore_screen_line( 0, prompt_line, display_buff );
  2340.    return( rc );
  2341. }
  2342.  
  2343.  
  2344. /*
  2345.  * Name:    get_block_numbers
  2346.  * Class:   helper function
  2347.  * Purpose: get the starting number and increment
  2348.  * Date:    June 5, 1991
  2349.  * Passed:  window:  pointer to current window
  2350.  *          block_num: address of number to start numbering
  2351.  *          block_inc: address of number to add to block_num
  2352.  *          just:      left or right justify numbers in block?
  2353.  */
  2354. int  get_block_numbers( TDE_WIN *window, long *block_num, long *block_inc,
  2355.                         int *just )
  2356. {
  2357. int prompt_line;
  2358. register int rc;
  2359. register int col;
  2360. char answer[MAX_COLS+2];
  2361. #if defined( __UNIX__ )
  2362.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  2363. #else
  2364.  char display_buff[(MAX_COLS+2)*2];
  2365. #endif
  2366.  
  2367.    prompt_line = window->bottom_line;
  2368.  
  2369.    /*
  2370.     * don't assume anything on starting number - start w/ null string.
  2371.     */
  2372.    answer[0] = '\0';
  2373.    /*
  2374.     * enter starting number
  2375.     */
  2376.    rc = get_name( block16, prompt_line, answer, g_display.message_color );
  2377.    if (answer[0] == '\0')
  2378.       rc = ERROR;
  2379.    if (rc != ERROR) {
  2380.       *block_num = atol( answer );
  2381.  
  2382.       /*
  2383.        * assume increment is 1
  2384.        */
  2385.       answer[0] = '1';
  2386.       answer[1] = '\0';
  2387.       /*
  2388.        * enter increment
  2389.        */
  2390.       rc = get_name( block17, prompt_line, answer, g_display.message_color );
  2391.       if (answer[0] == '\0')
  2392.          rc = ERROR;
  2393.       if (rc != ERROR) {
  2394.          *block_inc = atol( answer );
  2395.  
  2396.          /*
  2397.           * now, get left or right justification.  save contents of screen
  2398.           *  in a buffer, then write contents of buffer back to screen when
  2399.           *  we get through w/ justification.
  2400.           */
  2401.          save_screen_line( 0, prompt_line, display_buff );
  2402.          /*
  2403.           * left or right justify (l/r)?
  2404.           */
  2405.  
  2406.          assert( strlen( block18 ) < (size_t)g_display.ncols );
  2407.  
  2408.          strcpy( answer, block18 );
  2409.          s_output( answer, prompt_line, 0, g_display.message_color );
  2410.          col = strlen( answer );
  2411.          eol_clear( col, prompt_line, g_display.text_color );
  2412.          xygoto( col, prompt_line );
  2413.          rc = get_lr( );
  2414.          if (rc != ERROR) {
  2415.             *just = rc;
  2416.             rc = OK;
  2417.          }
  2418.          restore_screen_line( 0, prompt_line, display_buff );
  2419.       }
  2420.    }
  2421.    /*
  2422.     * if everything is everything then return code = OK.
  2423.     */
  2424.    return( rc );
  2425. }
  2426.  
  2427.  
  2428. /*
  2429.  * Name:    block_trim_trailing
  2430.  * Class:   primary editor function
  2431.  * Purpose: Trim trailing space in a LINE block.
  2432.  * Date:    June 5, 1991
  2433.  * Passed:  window:  pointer to current window
  2434.  * Notes:   Use copy_line and un_copy_line to do the work.
  2435.  */
  2436. int  block_trim_trailing( TDE_WIN *window )
  2437. {
  2438. int prompt_line;
  2439. int rc;
  2440. line_list_ptr p;             /* pointer to block line */
  2441. file_infos *file;
  2442. TDE_WIN *sw, s_w;
  2443. long er;
  2444. int  trailing;               /* save trailing setting */
  2445.  
  2446.    /*
  2447.     * make sure block is marked OK and that this is a LINE block
  2448.     */
  2449.    prompt_line = window->bottom_line;
  2450.    entab_linebuff( );
  2451.    rc = un_copy_line( window->ll, window, TRUE );
  2452.    check_block( );
  2453.    if (rc != ERROR && g_status.marked == TRUE) {
  2454.  
  2455.       trailing = mode.trailing;
  2456.       mode.trailing = TRUE;
  2457.       file = g_status.marked_file;
  2458.       if (file->block_type != LINE) {
  2459.          /*
  2460.           * can only trim trailing space in line blocks
  2461.           */
  2462.          error( WARNING, prompt_line, block21 );
  2463.          return( ERROR );
  2464.       }
  2465.  
  2466.       /*
  2467.        * initialize everything
  2468.        */
  2469.       sw = g_status.window_list;
  2470.       for (; ptoul( sw->file_info ) != ptoul( file );)
  2471.          sw = sw->next;
  2472.       if (mode.do_backups == TRUE) {
  2473.          file->modified = TRUE;
  2474.          rc = backup_file( sw );
  2475.       }
  2476.       dup_window_info( &s_w, sw );
  2477.  
  2478.       /*
  2479.        * set window to invisible so the un_copy_line function will
  2480.        * not display the lines while trimming.
  2481.        */
  2482.       s_w.visible = FALSE;
  2483.  
  2484.       p  = file->block_start;
  2485.       er = file->block_er;
  2486.       s_w.rline = file->block_br;
  2487.       for (; rc == OK && s_w.rline <= er  &&  !g_status.control_break; s_w.rline++) {
  2488.  
  2489.          /*
  2490.           * use the line buffer to trim space.
  2491.           */
  2492.          copy_line( p );
  2493.          rc = un_copy_line( p, &s_w, TRUE );
  2494.          p = p->next;
  2495.       }
  2496.  
  2497.       /*
  2498.        * IMPORTANT:  we need to reset the copied flag because the cursor may
  2499.        * not necessarily be on the last line of the block.
  2500.        */
  2501.       g_status.copied = FALSE;
  2502.       file->dirty = GLOBAL;
  2503.       mode.trailing = trailing;
  2504.       show_avail_mem( );
  2505.    }
  2506.    return( rc );
  2507. }
  2508.  
  2509.  
  2510. /*
  2511.  * Name:    block_email_reply
  2512.  * Class:   primary editor function
  2513.  * Purpose: insert the standard replay character '>' at beginning of line
  2514.  * Date:    June 5, 1992
  2515.  * Passed:  window:  pointer to current window
  2516.  * Notes:   it is customary to prepend "> " to the initial text and
  2517.  *             ">" to replies to replies to etc...
  2518.  */
  2519. int  block_email_reply( TDE_WIN *window )
  2520. {
  2521. int prompt_line;
  2522. int add;
  2523. int len;
  2524. int rc;
  2525. char *source;    /* source for block move to make room for c */
  2526. char *dest;      /* destination for block move */
  2527. line_list_ptr p;                     /* pointer to block line */
  2528. file_infos *file;
  2529. TDE_WIN *sw, s_w;
  2530. long er;
  2531.  
  2532.    /*
  2533.     * make sure block is marked OK and that this is a LINE block
  2534.     */
  2535.    prompt_line = window->bottom_line;
  2536.    entab_linebuff( );
  2537.    rc = un_copy_line( window->ll, window, TRUE );
  2538.    check_block( );
  2539.    if (rc != ERROR  &&  g_status.marked == TRUE) {
  2540.       file = g_status.marked_file;
  2541.       if (file->block_type != LINE) {
  2542.          /*
  2543.           * can only reply line blocks
  2544.           */
  2545.          error( WARNING, prompt_line, block25 );
  2546.          return( ERROR );
  2547.       }
  2548.  
  2549.       /*
  2550.        * find a window that points to the file with a marked block.
  2551.        */
  2552.       sw = g_status.window_list;
  2553.       for (; ptoul( sw->file_info ) != ptoul( file );)
  2554.          sw = sw->next;
  2555.       if (mode.do_backups == TRUE) {
  2556.          file->modified = TRUE;
  2557.          rc = backup_file( sw );
  2558.       }
  2559.  
  2560.       /*
  2561.        * use a local window structure to do the dirty work.  initialize
  2562.        *   the local window structure to the beginning of the marked
  2563.        *   block.
  2564.        */
  2565.       dup_window_info( &s_w, sw );
  2566.  
  2567.       /*
  2568.        * set s_w to invisible so the un_copy_line function will
  2569.        * not display the lines while doing block stuff.
  2570.        */
  2571.       s_w.visible = FALSE;
  2572.       s_w.rline = file->block_br;
  2573.       p  = file->block_start;
  2574.       er = file->block_er;
  2575.  
  2576.       /*
  2577.        * for each line in the marked block, prepend the reply character(s)
  2578.        */
  2579.       for (; rc == OK  &&  s_w.rline <= er  &&  !g_status.control_break;
  2580.                                                              s_w.rline++) {
  2581.  
  2582.          /*
  2583.           * put the line in the g_status.line_buff.  use add to count the
  2584.           *   number of characters to insert at the beginning of a line.
  2585.           *   the original reply uses "> ", while replies to replies use ">".
  2586.           */
  2587.          copy_line( p );
  2588.          if (*(p->line) == '>')
  2589.             add = 1;
  2590.          else
  2591.             add = 2;
  2592.  
  2593.          /*
  2594.           * see if the line has room to add the ">" character.  if there is
  2595.           *   room, move everything down to make room for the
  2596.           *   reply character(s).
  2597.           */
  2598.          len = g_status.line_buff_len;
  2599.          if (len + add < MAX_LINE_LENGTH) {
  2600.             source = g_status.line_buff;
  2601.             dest = source + add;
  2602.  
  2603.             assert( len >= 0 );
  2604.             assert( len < MAX_LINE_LENGTH );
  2605.             assert( len + add < MAX_LINE_LENGTH );
  2606.  
  2607.             memmove( dest, source, len );
  2608.             *source = '>';
  2609.             if (add > 1)
  2610.               *(source+1) = ' ';
  2611.             g_status.line_buff_len = len + add;
  2612.             rc = un_copy_line( p, &s_w, TRUE );
  2613.          }
  2614.          p = p->next;
  2615.          g_status.copied = FALSE;
  2616.       }
  2617.  
  2618.       /*
  2619.        * IMPORTANT:  we need to reset the copied flag because the cursor may
  2620.        * not necessarily be on the last line of the block.
  2621.        */
  2622.       g_status.copied = FALSE;
  2623.       file->dirty = GLOBAL;
  2624.       show_avail_mem( );
  2625.    }
  2626.    return( OK );
  2627. }
  2628.  
  2629.  
  2630. /*
  2631.  * Name:    block_convert_case
  2632.  * Class:   primary editor function
  2633.  * Purpose: convert characters to lower case, upper case, strip hi bits,
  2634.  *          or e-mail functions
  2635.  * Date:    June 5, 1991
  2636.  * Passed:  window:  pointer to current window
  2637.  */
  2638. int  block_convert_case( TDE_WIN *window )
  2639. {
  2640. int  len;
  2641. int  block_type;
  2642. line_list_ptr begin;
  2643. register file_infos *file;
  2644. TDE_WIN *sw;
  2645. long number;
  2646. long er;
  2647. unsigned int count;
  2648. int  bc, ec;
  2649. int  block_len;
  2650. int  rc;
  2651. void (*char_func)( text_ptr, unsigned int );
  2652.  
  2653.    /*
  2654.     * make sure block is marked OK
  2655.     */
  2656.    entab_linebuff( );
  2657.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2658.       return( ERROR );
  2659.    rc = OK;
  2660.    check_block( );
  2661.    if (g_status.marked == TRUE) {
  2662.  
  2663.       /*
  2664.        * set char_func() to the required block function in tdeasm.c
  2665.        */
  2666.       switch (g_status.command) {
  2667.          case BlockUpperCase  :
  2668.             char_func = upper_case;
  2669.             break;
  2670.          case BlockLowerCase  :
  2671.             char_func = lower_case;
  2672.             break;
  2673.          case BlockRot13      :
  2674.             char_func = rot13;
  2675.             break;
  2676.          case BlockFixUUE     :
  2677.             char_func = fix_uue;
  2678.             break;
  2679.          case BlockStripHiBit :
  2680.             char_func = strip_hi;
  2681.             break;
  2682.          default :
  2683.             return( ERROR );
  2684.       }
  2685.  
  2686.       file  = g_status.marked_file;
  2687.       file->modified = TRUE;
  2688.       if (mode.do_backups == TRUE) {
  2689.          sw = g_status.window_list;
  2690.          for (; ptoul( sw->file_info ) != ptoul( file );)
  2691.             sw = sw->next;
  2692.          rc = backup_file( sw );
  2693.       }
  2694.  
  2695.       if (rc == OK) {
  2696.          block_type = file->block_type;
  2697.          ec = file->block_ec;
  2698.  
  2699.          begin  = file->block_start;
  2700.  
  2701.          er = file->block_er;
  2702.          block_len = ec + 1 - file->block_bc;
  2703.          for (number=file->block_br; number <= er; number++) {
  2704.             begin->dirty = TRUE;
  2705.             count = len = begin->len;
  2706.             bc = 0;
  2707.             if (block_type == STREAM) {
  2708.                if (number == file->block_br) {
  2709.                   bc = file->block_bc;
  2710.                   if (len < file->block_bc) {
  2711.                      count = 0;
  2712.                      bc = len;
  2713.                   }
  2714.                }
  2715.                if (number == file->block_er) {
  2716.                   if (ec < len)
  2717.                      ec = len;
  2718.                   count = ec - bc + 1;
  2719.                }
  2720.             } else if (block_type == BOX) {
  2721.                bc = file->block_bc;
  2722.                count =  len >= ec ? block_len : len - bc;
  2723.             }
  2724.             if (len > bc) {
  2725.  
  2726.                assert( count < MAX_LINE_LENGTH );
  2727.                assert( bc >= 0 );
  2728.                assert( bc < MAX_LINE_LENGTH );
  2729.  
  2730.                (*char_func)( begin->line+bc, count );
  2731.             }
  2732.             begin = begin->next;
  2733.          }
  2734.  
  2735.          /*
  2736.           * IMPORTANT:  we need to reset the copied flag because the cursor may
  2737.           * not necessarily be on the last line of the block.
  2738.           */
  2739.          g_status.copied = FALSE;
  2740.          file->dirty = GLOBAL;
  2741.       }
  2742.    } else
  2743.       rc = ERROR;
  2744.    return( rc );
  2745. }
  2746.  
  2747.  
  2748. /*
  2749.  * Name:    upper_case
  2750.  * Purpose: To convert all lower case characters to upper characters
  2751.  * Date:    June 5, 1991
  2752.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  2753.  * Passed:  s:    the starting point
  2754.  *          count: number of characters to convert
  2755.  * Returns: none
  2756.  * Notes:   upper_lower[] is defined in bottom of prompts.h.  modify as
  2757.  *           needed for your favorite language.
  2758.  */
  2759. void upper_case( text_ptr s, size_t count )
  2760. {
  2761.    if (s != NULL) {
  2762.       for (; count > 0; s++, count-- ) {
  2763.          if (bj_islower( *s ))            /* if lowercase letter */
  2764.             *s = upper_lower[*s];       /*    then upcase it   */
  2765.       }
  2766.    }
  2767. }
  2768.  
  2769.  
  2770. /*
  2771.  * Name:    lower_case
  2772.  * Purpose: To convert all upper case characters to lower characters
  2773.  * Date:    June 5, 1991
  2774.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  2775.  * Passed:  s:    the starting point
  2776.  *          count: number of characters to convert
  2777.  * Returns: none
  2778.  * Notes:   upper_lower[] is defined in bottom of prompts.h.  modify as
  2779.  *           needed for your favorite language.
  2780.  */
  2781. void lower_case( text_ptr s, size_t count )
  2782. {
  2783.    if (s != NULL) {
  2784.       for (; count > 0; s++, count-- ) {
  2785.          if (bj_isupper( *s ))          /* if uppercase letter */
  2786.             *s = upper_lower[*s];       /*    then lowcase it  */
  2787.       }
  2788.    }
  2789. }
  2790.  
  2791.  
  2792. /*
  2793.  * Name:    rot13
  2794.  * Purpose: To rotate all alphabet characters by 13
  2795.  * Date:    June 5, 1991
  2796.  * Passed:  s:    the starting point
  2797.  *          count: number of characters to convert
  2798.  * Returns: none
  2799.  * Notes:   simple rot13
  2800.  *          i really don't know how to handle rot13 for alphabets
  2801.  *           other than English.
  2802.  */
  2803. void rot13( text_ptr s, size_t count )
  2804. {
  2805. register size_t c;
  2806.  
  2807.    if (s != NULL) {
  2808.       for (; count > 0; s++, count-- ) {
  2809.          c = *s;
  2810.          if (c >= 'a'  &&  c <=  'm')
  2811.             c += 13;
  2812.          else if (c >= 'n'  &&  c <= 'z')
  2813.             c -= 13;
  2814.          else if (c >= 'A'  &&  c <=  'M')
  2815.             c += 13;
  2816.          else if (c >= 'N'  &&  c <= 'Z')
  2817.             c -= 13;
  2818.          *s = (unsigned char)c;
  2819.       }
  2820.    }
  2821. }
  2822.  
  2823.  
  2824. /*
  2825.  * Name:    fix_uue
  2826.  * Purpose: To fix EBCDIC ==> ASCII translation problem
  2827.  * Date:    June 5, 1991
  2828.  * Passed:  s:    the starting point
  2829.  *          count: number of characters to convert
  2830.  * Returns: none
  2831.  * Notes:   to fix the EBCDIC to ASCII translation problem, three characters
  2832.  *           need to be changed,  0x5d -> 0x7c, 0xd5 -> 0x5b, 0xe5 -> 0x5d
  2833.  */
  2834. void fix_uue( text_ptr s, size_t  count )
  2835. {
  2836.    if (s != NULL) {
  2837.       for (; count > 0; s++, count-- ) {
  2838.          switch (*s) {
  2839.             case 0x5d :
  2840.                *s = 0x7c;
  2841.                break;
  2842.             case 0xd5 :
  2843.                *s = 0x5b;
  2844.                break;
  2845.             case 0xe5 :
  2846.                *s = 0x5d;
  2847.                break;
  2848.             default :
  2849.                break;
  2850.          }
  2851.       }
  2852.    }
  2853. }
  2854.  
  2855.  
  2856. /*
  2857.  * Name:    strip_hi
  2858.  * Purpose: To strip bit 7 from characters
  2859.  * Date:    June 5, 1991
  2860.  * Passed:  s:    the starting point, which should be normalized to a segment
  2861.  *          count: number of characters to strip (size_t)
  2862.  *                 count should not be greater than MAX_LINE_LENGTH
  2863.  * Returns: none
  2864.  * Notes:   this function is useful on WordStar files.  to make a WordStar
  2865.  *           file readable, the hi bits need to be anded off.
  2866.  *          incidentally, soft CRs and LFs may be converted to hard CRs
  2867.  *           and LFs.  this function makes no attempt to split lines
  2868.  *           when soft returns are converted to hard returns.
  2869.  */
  2870. void strip_hi( text_ptr s, size_t count )
  2871. {
  2872.    if (s != NULL) {
  2873.       for (; count > 0; s++, count-- ) {
  2874.          if (*s >= 0x80)
  2875.             *s &= 0x7f;
  2876.       }
  2877.    }
  2878. }
  2879.